home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 7
/
Apprentice-Release7.iso
/
Environments
/
PowerLisp 2.01
/
Supplemental Documentation
/
Documentation
/
Chapter 12. Numbers
< prev
next >
Wrap
Text File
|
1995-03-27
|
132KB
|
3,162 lines
Common Lisp the Language, 2nd Edition
-------------------------------------------------------------------------------
12. Numbers
Common Lisp provides several different representations for numbers. These
representations may be divided into four categories: integers, ratios,
floating-point numbers, and complex numbers. Many numeric functions will accept
any kind of number; they are generic. Other functions accept only certain kinds
of numbers.
[change_begin]
Note that this remark, predating the design of the Common Lisp Object System,
uses the term ``generic'' in a generic sense and not necessarily in the
technical sense used by CLOS (see chapter 2).
[change_end]
In general, numbers in Common Lisp are not true objects; eq cannot be counted
upon to operate on them reliably. In particular, it is possible that the
expression
(let ((x z) (y z)) (eq x y))
may be false rather than true if the value of z is a number.
-------------------------------------------------------------------------------
Rationale: This odd breakdown of eq in the case of numbers allows the
implementor enough design freedom to produce exceptionally efficient numerical
code on conventional architectures. MacLisp requires this freedom, for example,
in order to produce compiled numerical code equal in speed to Fortran. Common
Lisp makes this same restriction, if not for this freedom, then at least for
the sake of compatibility.
-------------------------------------------------------------------------------
If two objects are to be compared for ``identity,'' but either might be a
number, then the predicate eql is probably appropriate; if both objects are
known to be numbers, then = may be preferable.
-------------------------------------------------------------------------------
* Precision, Contagion, and Coercion
* Predicates on Numbers
* Comparisons on Numbers
* Arithmetic Operations
* Irrational and Transcendental Functions
o Exponential and Logarithmic Functions
o Trigonometric and Related Functions
o Branch Cuts, Principal Values, and Boundary Conditions in the
Complex Plane
* Type Conversions and Component Extractions on Numbers
* Logical Operations on Numbers
* Byte Manipulation Functions
* Random Numbers
* Implementation Parameters
-------------------------------------------------------------------------------
12.1. Precision, Contagion, and Coercion
In general, computations with floating-point numbers are only approximate. The
precision of a floating-point number is not necessarily correlated at all with
the accuracy of that number. For instance, 3.142857142857142857 is a more
precise approximation to than 3.14159, but the latter is more accurate. The
precision refers to the number of bits retained in the representation. When an
operation combines a short floating-point number with a long one, the result
will be a long floating-point number. This rule is made to ensure that as much
accuracy as possible is preserved; however, it is by no means a guarantee.
Common Lisp numerical routines do assume, however, that the accuracy of an
argument does not exceed its precision. Therefore when two small floating-point
numbers are combined, the result will always be a small floating-point number.
This assumption can be overridden by first explicitly converting a small
floating-point number to a larger representation. (Common Lisp never converts
automatically from a larger size to a smaller one.)
Rational computations cannot overflow in the usual sense (though of course
there may not be enough storage to represent one), as integers and ratios may
in principle be of any magnitude. Floating-point computations may get exponent
overflow or underflow; this is an error.
[change_begin]
X3J13 voted in June 1989 (FLOAT-UNDERFLOW) to address certain problems
relating to floating-point overflow and underflow, but certain parts of the
proposed solution were not adopted, namely to add the macro
without-floating-underflow-traps to the language and to require certain
behavior of floating-point overflow and underflow. The committee agreed that
this area of the language requires more discussion before a solution is
standardized.
For the record, the proposal that was considered and rejected (for the nonce)
introduced a macro without-floating-underflow-traps that would execute its body
in such a way that, within its dynamic extent, a floating-point underflow must
not signal an error but instead must produce either a denormalized number or
zero as the result. The rejected proposal also specified the following
treatment of overflow and underflow:
* A floating-point computation that overflows should signal an error of
type floating-point-overflow.
* Unless the dynamic extent of a use of without-floating-underflow-traps, a
floating-point computation that underflows should signal an error of type
floating-point-underflow. A result that can be represented only in
denormalized form must be considered an underflow in implementations that
support denormalized floating-point numbers.
These points refer to conditions floating-point-overflow and
floating-point-underflow that were approved by X3J13 and are described in
section 29.5.
[change_end]
When rational and floating-point numbers are compared or combined by a
numerical function, the rule of floating-point contagion is followed: when a
rational meets a floating-point number, the rational is first converted to a
floating-point number of the same format. For functions such as + that take
more than two arguments, it may be that part of the operation is carried out
exactly using rationals and then the rest is done using floating-point
arithmetic.
[change_begin]
X3J13 voted in January 1989 (CONTAGION-ON-NUMERICAL-COMPARISONS) to apply the
rule of floating-point contagion stated above to the case of combining rational
and floating-point numbers. For comparing, the following rule is to be used
instead: When a rational number and a floating-point number are to be compared
by a numerical function, in effect the floating-point number is first converted
to a rational number as if by the function rational, and then an exact
comparison of two rational numbers is performed. It is of course valid to use a
more efficient implementation than actually calling the function rational, as
long as the result of the comparison is the same. In the case of complex
numbers, the real and imaginary parts are handled separately.
-------------------------------------------------------------------------------
Rationale: In general, accuracy cannot be preserved in combining operations,
but it can be preserved in comparisons, and preserving it makes that part of
Common Lisp algebraically a bit more tractable. In particular, this change
prevents the breakdown of transitivity. Let a be the result of (/ 10.0
single-float-epsilon), and let j be the result of (floor a). (Note that (= a (+
a 1.0)) is true, by the definition of single-float-epsilon.) Under the old
rules, all of (<= a j), (< j (+ j 1)), and (<= (+ j 1) a) would be true;
transitivity would then imply that (< a a) ought to be true, but of course it
is false, and therefore transitivity fails. Under the new rule, however, (<= (+
j 1) a) is false.
-------------------------------------------------------------------------------
[change_end]
For functions that are mathematically associative (and possibly commutative), a
Common Lisp implementation may process the arguments in any manner consistent
with associative (and possibly commutative) rearrangement. This does not affect
the order in which the argument forms are evaluated, of course; that order is
always left to right, as in all Common Lisp function calls. What is left loose
is the order in which the argument values are processed. The point of all this
is that implementations may differ in which automatic coercions are applied
because of differing orders of argument processing. As an example, consider
this expression:
(+ 1/3 2/3 1.0D0 1.0 1.0E-15)
One implementation might process the arguments from left to right, first adding
1/3 and 2/3 to get 1, then converting that to a double-precision floating-point
number for combination with 1.0D0, then successively converting and adding 1.0
and 1.0E-15. Another implementation might process the arguments from right to
left, first performing a single-precision floating-point addition of 1.0 and
1.0E-15 (and probably losing some accuracy in the process!), then converting
the sum to double precision and adding 1.0D0, then converting 2/3 to
double-precision floating-point and adding it, and then converting 1/3 and
adding that. A third implementation might first scan all the arguments, process
all the rationals first to keep that part of the computation exact, then find
an argument of the largest floating-point format among all the arguments and
add that, and then add in all other arguments, converting each in turn (all in
a perhaps misguided attempt to make the computation as accurate as possible).
In any case, all three strategies are legitimate. The user can of course
control the order of processing explicitly by writing several calls; for
example:
(+ (+ 1/3 2/3) (+ 1.0D0 1.0E-15) 1.0)
The user can also control all coercions simply by writing calls to coercion
functions explicitly.
In general, then, the type of the result of a numerical function is a
floating-point number of the largest format among all the floating-point
arguments to the function; but if the arguments are all rational, then the
result is rational (except for functions that can produce mathematically
irrational results, in which case a single-format floating-point number may
result).
There is a separate rule of complex contagion. As a rule, complex numbers never
result from a numerical function unless one or more of the arguments is
complex. (Exceptions to this rule occur among the irrational and transcendental
functions, specifically expt, log, sqrt, asin, acos, acosh, and atanh; see
section 12.5.) When a non-complex number meets a complex number, the
non-complex number is in effect first converted to a complex number by
providing an imaginary part of zero.
If any computation produces a result that is a ratio of two integers such that
the denominator evenly divides the numerator, then the result is immediately
converted to the equivalent integer. This is called the rule of rational
canonicalization.
If the result of any computation would be a complex rational with a zero
imaginary part, the result is immediately converted to a non-complex rational
number by taking the real part. This is called the rule of complex
canonicalization. Note that this rule does not apply to complex numbers whose
components are floating-point numbers. Whereas #C(5 0) and 5 are not distinct
values in Common Lisp (they are always eql), #C(5.0 0.0) and 5.0 are always
distinct values in Common Lisp (they are never eql, although they are equalp).
-------------------------------------------------------------------------------
12.2. Predicates on Numbers
Each of the following functions tests a single number for a specific property.
Each function requires that its argument be a number; to call one with a
non-number is an error.
[Function]
zerop number
This predicate is true if number is zero (the integer zero, a floating-point
zero, or a complex zero), and is false otherwise. Regardless of whether an
implementation provides distinct representations for positive and negative
floating-point zeros, (zerop -0.0) is always true. It is an error if the
argument number is not a number.
[Function]
plusp number
This predicate is true if number is strictly greater than zero, and is false
otherwise. It is an error if the argument number is not a non-complex number.
[Function]
minusp number
This predicate is true if number is strictly less than zero, and is false
otherwise. Regardless of whether an implementation provides distinct
representations for positive and negative floating-point zeros, (minusp -0.0)
is always false. (The function float-sign may be used to distinguish a negative
zero.) It is an error if the argument number is not a non-complex number.
[Function]
oddp integer
This predicate is true if the argument integer is odd (not divisible by 2), and
otherwise is false. It is an error if the argument is not an integer.
[Function]
evenp integer
This predicate is true if the argument integer is even (divisible by 2), and
otherwise is false. It is an error if the argument is not an integer.
See also the data-type predicates integerp, rationalp, floatp, complexp, and
numberp.
-------------------------------------------------------------------------------
12.3. Comparisons on Numbers
Each of the functions in this section requires that its arguments all be
numbers; to call one with a non-number is an error. Unless otherwise specified,
each works on all types of numbers, automatically performing any required
coercions when arguments are of different types.
[Function]
= number &rest more-numbers
/= number &rest more-numbers
< number &rest more-numbers
> number &rest more-numbers
<= number &rest more-numbers
>= number &rest more-numbers
These functions each take one or more arguments. If the sequence of arguments
satisfies a certain condition:
= all the same
/= all different
< monotonically increasing
> monotonically decreasing
<= monotonically nondecreasing
>= monotonically nonincreasing
then the predicate is true, and otherwise is false. Complex numbers may be
compared using = and /=, but the others require non-complex arguments. Two
complex numbers are considered equal by = if their real parts are equal and
their imaginary parts are equal according to =. A complex number may be
compared with a non-complex number with = or /=. For example:
(= 3 3) is true. (/= 3 3) is false.
(= 3 5) is false. (/= 3 5) is true.
(= 3 3 3 3) is true. (/= 3 3 3 3) is false.
(= 3 3 5 3) is false. (/= 3 3 5 3) is false.
(= 3 6 5 2) is false. (/= 3 6 5 2) is true.
(= 3 2 3) is false. (/= 3 2 3) is false.
(< 3 5) is true. (<= 3 5) is true.
(< 3 -5) is false. (<= 3 -5) is false.
(< 3 3) is false. (<= 3 3) is true.
(< 0 3 4 6 7) is true. (<= 0 3 4 6 7) is true.
(< 0 3 4 4 6) is false. (<= 0 3 4 4 6) is true.
(> 4 3) is true. (>= 4 3) is true.
(> 4 3 2 1 0) is true. (>= 4 3 2 1 0) is true.
(> 4 3 3 2 0) is false. (>= 4 3 3 2 0) is true.
(> 4 3 1 2 0) is false. (>= 4 3 1 2 0) is false.
(= 3) is true. (/= 3) is true.
(< 3) is true. (<= 3) is true.
(= 3.0 #C(3.0 0.0)) is true. (/= 3.0 #C(3.0 1.0)) is true.
(= 3 3.0) is true. (= 3.0s0 3.0d0) is true.
(= 0.0 -0.0) is true. (= 5/2 2.5) is true.
(> 0.0 -0.0) is false. (= 0 -0.0) is true.
With two arguments, these functions perform the usual arithmetic comparison
tests. With three or more arguments, they are useful for range checks, as shown
in the following example:
(<= 0 x 9) ;true if x is between 0 and 9, inclusive
(< 0.0 x 1.0) ;true if x is between 0.0 and 1.0, exclusive
(< -1 j (length s)) ;true if j is a valid index for s
(<= 0 j k (- (length s) 1)) ;true if j and k are each valid
; indices for s and jk
-------------------------------------------------------------------------------
Rationale: The ``unequality'' relation is called /= rather than <> (the name
used in Pascal) for two reasons. First, /= of more than two arguments is not
the same as the or of < and > of those same arguments. Second, unequality is
meaningful for complex numbers even though < and > are not. For both reasons it
would be misleading to associate unequality with the names of < and >.
-------------------------------------------------------------------------------
Compatibility note: In Common Lisp, the comparison operations perform
``mixed-mode'' comparisons: (= 3 3.0) is true. In MacLisp, there must be
exactly two arguments, and they must be either both fixnums or both
floating-point numbers. To compare two numbers for numerical equality and type
equality, use eql.
-------------------------------------------------------------------------------
[Function]
max number &rest more-numbers
min number &rest more-numbers
The arguments may be any non-complex numbers. max returns the argument that is
greatest (closest to positive infinity). min returns the argument that is least
(closest to negative infinity).
For max, if the arguments are a mixture of rationals and floating-point
numbers, and the largest argument is a rational, then the implementation is
free to produce either that rational or its floating-point approximation; if
the largest argument is a floating-point number of a smaller format than the
largest format of any floating-point argument, then the implementation is free
to return the argument in its given format or expanded to the larger format.
More concisely, the implementation has the choice of returning the largest
argument as is or applying the rules of floating-point contagion, taking all
the arguments into consideration for contagion purposes. Also, if two or more
of the arguments are equal, then any one of them may be chosen as the value to
return. Similar remarks apply to min (replacing ``largest argument'' by
``smallest argument'').
(max 6 12) => 12 (min 6 12) => 6
(max -6 -12) => -6 (min -6 -12) => -12
(max 1 3 2 -7) => 3 (min 1 3 2 -7) => -7
(max -2 3 0 7) => 7 (min -2 3 0 7) => -2
(max 3) => 3 (min 3) => 3
(max 5.0 2) => 5.0 (min 5.0 2) => 2 or 2.0
(max 3.0 7 1) => 7 or 7.0 (min 3.0 7 1) => 1 or 1.0
(max 1.0s0 7.0d0) => 7.0d0
(min 1.0s0 7.0d0) => 1.0s0 or 1.0d0
(max 3 1 1.0s0 1.0d0) => 3 or 3.0d0
(min 3 1 1.0s0 1.0d0) => 1 or 1.0s0 or 1.0d0
-------------------------------------------------------------------------------
12.4. Arithmetic Operations
Each of the functions in this section requires that its arguments all be
numbers; to call one with a non-number is an error. Unless otherwise specified,
each works on all types of numbers, automatically performing any required
coercions when arguments are of different types.
[Function]
+ &rest numbers
This returns the sum of the arguments. If there are no arguments, the result is
0, which is an identity for this operation.
-------------------------------------------------------------------------------
Compatibility note: While + is compatible with its use in Lisp Machine Lisp, it
is incompatible with MacLisp, which uses + for fixnum-only addition.
-------------------------------------------------------------------------------
[Function]
- number &rest more-numbers
The function -, when given one argument, returns the negative of that argument.
The function -, when given more than one argument, successively subtracts from
the first argument all the others, and returns the result. For example, (- 3 4
5) => -6.
-------------------------------------------------------------------------------
Compatibility note: While - is compatible with its use in Lisp Machine Lisp, it
is incompatible with MacLisp, which uses - for fixnum-only subtraction. Also, -
differs from difference as used in most Lisp systems in the case of one
argument.
-------------------------------------------------------------------------------
[Function]
* &rest numbers
This returns the product of the arguments. If there are no arguments, the
result is 1, which is an identity for this operation.
-------------------------------------------------------------------------------
Compatibility note: While * is compatible with its use in Lisp Machine Lisp, it
is incompatible with MacLisp, which uses * for fixnum-only multiplication.
-------------------------------------------------------------------------------
[Function]
/ number &rest more-numbers
The function /, when given more than one argument, successively divides the
first argument by all the others and returns the result.
[change_begin]
It is generally accepted that it is an error for any argument other than the
first to be zero.
[change_end]
With one argument, / reciprocates the argument.
[change_begin]
It is generally accepted that it is an error in this case for the argument to
be zero.
[change_end]
/ will produce a ratio if the mathematical quotient of two integers is not an
exact integer. For example:
(/ 12 4) => 3
(/ 13 4) => 13/4
(/ -8) => -1/8
(/ 3 4 5) => 3/20
To divide one integer by another producing an integer result, use one of the
functions floor, ceiling, truncate, or round.
If any argument is a floating-point number, then the rules of floating-point
contagion apply.
-------------------------------------------------------------------------------
Compatibility note: What / does is totally unlike what the usual // or quotient
operator does. In most Lisp systems, quotient behaves like / except when
dividing integers, in which case it behaves like truncate of two arguments;
this behavior is mathematically intractable, leading to such anomalies as
(quotient 1.0 2.0) => 0.5 but (quotient 1 2) => 0
In contrast, the Common Lisp function / produces these results:
(/ 1.0 2.0) => 0.5 and (/ 1 2) => 1/2
In practice quotient is used only when one is sure that both arguments are
integers, or when one is sure that at least one argument is a floating-point
number. / is tractable for its purpose and works for any numbers.
-------------------------------------------------------------------------------
[Function]
1+ number
1- number
(1+ x) is the same as (+ x 1).
(1- x) is the same as (- x 1). Note that the short name may be confusing: (1-
x) does not mean 1-x; rather, it means x-1.
-------------------------------------------------------------------------------
Rationale: These are included primarily for compatibility with MacLisp and Lisp
Machine Lisp. Some programmers prefer always to write (+ x 1) and (- x 1)
instead of (1+ x) and (1- x).
-------------------------------------------------------------------------------
Implementation note: Compiler writers are very strongly encouraged to ensure
that (1+ x) and (+ x 1) compile into identical code, and similarly for (1- x)
and (- x 1), to avoid pressure on a Lisp programmer to write possibly less
clear code for the sake of efficiency. This can easily be done as a
source-language transformation.
-------------------------------------------------------------------------------
[Macro]
incf place [delta]
decf place [delta]
The number produced by the form delta is added to (incf) or subtracted from
(decf) the number in the generalized variable named by place, and the sum is
stored back into place and returned. The form place may be any form acceptable
as a generalized variable to setf. If delta is not supplied, then the number in
place is changed by 1. For example:
(setq n 0)
(incf n) => 1 and now n => 1
(decf n 3) => -2 and now n => -2
(decf n -5) => 3 and now n => 3
(decf n) => 2 and now n => 2
The effect of (incf place delta) is roughly equivalent to
(setf place (+ place delta))
except that the latter would evaluate any subforms of place twice, whereas incf
takes care to evaluate them only once. Moreover, for certain place forms incf
may be significantly more efficient than the setf version.
[change_begin]
X3J13 voted in March 1988 (PUSH-EVALUATION-ORDER) to clarify order of
evaluation (see section 7.2).
[change_end]
[Function]
conjugate number
This returns the complex conjugate of number. The conjugate of a non-complex
number is itself. For a complex number z,
(conjugate z) == (complex (realpart z) (- (imagpart z)))
For example:
(conjugate #C(3/5 4/5)) => #C(3/5 -4/5)
(conjugate #C(0.0D0 -1.0D0)) => #C(0.0D0 1.0D0)
(conjugate 3.7) => 3.7
[Function]
gcd &rest integers
This returns the greatest common divisor of all the arguments, which must be
integers. The result of gcd is always a non-negative integer. If one argument
is given, its absolute value is returned. If no arguments are given, gcd
returns 0, which is an identity for this operation. For three or more
arguments,
(gcd a b c ... z) == (gcd (gcd a b) c ... z)
Here are some examples of the use of gcd:
(gcd 91 -49) => 7
(gcd 63 -42 35) => 7
(gcd 5) => 5
(gcd -4) => 4
(gcd) => 0
[Function]
lcm integer &rest more-integers
This returns the least common multiple of its arguments, which must be
integers. The result of lcm is always a non-negative integer. For two arguments
that are not both zero,
(lcm a b) == (/ (abs (* a b)) (gcd a b))
If one or both arguments are zero,
(lcm a 0) == (lcm 0 a) == 0
For one argument, lcm returns the absolute value of that argument. For three or
more arguments,
(lcm a b c ... z) == (lcm (lcm a b) c ... z)
Some examples:
(lcm 14 35) => 70
(lcm 0 5) => 0
(lcm 1 2 3 4 5 6) => 60
Mathematically, (lcm) should return infinity. Because Common Lisp does not have
a representation for infinity, lcm, unlike gcd, always requires at least one
argument.
[change_begin]
X3J13 voted in January 1989 (LCM-NO-ARGUMENTS) to specify that (lcm) => 1.
This is one of my biggest boners. The identity for lcm is of course 1, not
infinity, and so (lcm) ought to have been defined to return 1. Sorry about
that, though in point of fact very few users have complained to me that this
mistake in the first edition has cramped their programming style.
[change_end]
-------------------------------------------------------------------------------
12.5. Irrational and Transcendental Functions
Common Lisp provides no data type that can accurately represent irrational
numerical values. The functions in this section are described as if the results
were mathematically accurate, but actually they all produce floating-point
approximations to the true mathematical result in the general case. In some
places mathematical identities are set forth that are intended to elucidate the
meanings of the functions; however, two mathematically identical expressions
may be computationally different because of errors inherent in the
floating-point approximation process.
When the arguments to a function in this section are all rational and the true
mathematical result is also (mathematically) rational, then unless otherwise
noted an implementation is free to return either an accurate result of type
rational or a single-precision floating-point approximation. If the arguments
are all rational but the result cannot be expressed as a rational number, then
a single-precision floating-point approximation is always returned.
[change_begin]
X3J13 voted in March 1989 (COMPLEX-RATIONAL-RESULT) to clarify that the
provisions of the previous paragraph apply to complex numbers. If the arguments
to a function are all of type (or rational (complex rational)) and the true
mathematical result is (mathematically) a complex number with rational real and
imaginary parts, then unless otherwise noted an implementation is free to
return either an accurate result of type (or rational (complex rational)) or a
single-precision floating-point approximation of type single-float (permissible
only if the imaginary part of the true mathematical result is zero) or (complex
single-float). If the arguments are all of type (or rational (complex
rational)) but the result cannot be expressed as a rational or complex rational
number, then the returned value will be of type single-float (permissible only
if the imaginary part of the true mathematical result is zero) or (complex
single-float).
[change_end]
The rules of floating-point contagion and complex contagion are effectively
obeyed by all the functions in this section except expt, which treats some
cases of rational exponents specially. When, possibly after contagious
conversion, all of the arguments are of the same floating-point or complex
floating-point type, then the result will be of that same type unless otherwise
noted.
-------------------------------------------------------------------------------
Implementation note: There is a ``floating-point cookbook'' by Cody and Waite
[14] that may be a useful aid in implementing the functions defined in this
section.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
* Exponential and Logarithmic Functions
* Trigonometric and Related Functions
* Branch Cuts, Principal Values, and Boundary Conditions in the Complex
Plane
-------------------------------------------------------------------------------
12.5.1. Exponential and Logarithmic Functions
Along with the usual one-argument and two-argument exponential and logarithm
functions, sqrt is considered to be an exponential function, because it raises
a number to the power 1/2.
[Function]
exp number
Returns e raised to the power number, where e is the base of the natural
logarithms.
[Function]
expt base-number power-number
Returns base-number raised to the power power-number. If the base-number is of
type rational and the power-number is an integer, the calculation will be exact
and the result will be of type rational; otherwise a floating-point
approximation may result.
[change_begin]
X3J13 voted in March 1989 (COMPLEX-RATIONAL-RESULT) to clarify that
provisions similar to those of the previous paragraph apply to complex numbers.
If the base-number is of type (complex rational) and the power-number is an
integer, the calculation will also be exact and the result will be of type (or
rational (complex rational)); otherwise a floating-point or complex
floating-point approximation may result.
[change_end]
When power-number is 0 (a zero of type integer), then the result is always the
value 1 in the type of base-number, even if the base-number is zero (of any
type). That is:
(expt x 0) == (coerce 1 (type-of x))
If the power-number is a zero of any other data type, then the result is also
the value 1, in the type of the arguments after the application of the
contagion rules, with one exception: it is an error if base-number is zero when
the power-number is a zero not of type integer.
Implementations of expt are permitted to use different algorithms for the cases
of a rational power-number and a floating-point power-number; the motivation is
that in many cases greater accuracy can be achieved for the case of a rational
power-number. For example, (expt pi 16) and (expt pi 16.0) may yield slightly
different results if the first case is computed by repeated squaring and the
second by the use of logarithms. Similarly, an implementation might choose to
compute (expt x 3/2) as if it had been written (sqrt (expt x 3)), perhaps
producing a more accurate result than would (expt x 1.5). It is left to the
implementor to determine the best strategies.
[change_begin]
X3J13 voted in January 1989 (EXPT-RATIO) to clarify that the preceding remark
is in error, because (sqrt (expt x 3)) does not produce the same value as (expt
x 3/2) in most cases, and to specify that the specification of the principal
value of expt as given in section 12.5.3 should be regarded as definitive.
As an example of the difficulty, let . Then , but . Another example is
x=-1; then , but .
[change_end]
The result of expt can be a complex number, even when neither argument is
complex, if base-number is negative and power-number is not an integer. The
result is always the principal complex value. Note that (expt -8 1/3) is not
permitted to return -2; while -2 is indeed one of the cube roots of -8, it is
not the principal cube root, which is a complex number approximately equal to
#C(1.0 1.73205).
[change_begin]
Notice of correction. The first edition gave the incorrect value #C(0.5
1.73205) for the principal cube root of -8. The correct value is #C(1.0
1.73205), that is, 1+SQRT(3)i. I simply don't know what I was thinking of!
[change_end]
[Function]
log number &optional base
Returns the logarithm of number in the base base, which defaults to e, the base
of the natural logarithms. For example:
(log 8.0 2) => 3.0
(log 100.0 10) => 2.0
The result of (log 8 2) may be either 3 or 3.0, depending on the
implementation.
Note that log may return a complex result when given a non-complex argument if
the argument is negative. For example:
(log -1.0) == (complex 0.0 (float pi 0.0))
[change_begin]
X3J13 voted in January 1989 (IEEE-ATAN-BRANCH-CUT) to specify certain
floating-point behavior when minus zero is supported. As a part of that vote it
approved a mathematical definition of complex logarithm in terms of real
logarithm, absolute value, arc tangent of two real arguments, and the phase
function as
Logarithm log|z| + i phase z
This specifies the branch cuts precisely whether minus zero is supported or
not; see phase and atan.
[change_end]
[Function]
sqrt number
Returns the principal square root of number. If the number is not complex but
is negative, then the result will be a complex number. For example:
(sqrt 9.0) => 3.0
(sqrt -9.0) => #c(0.0 3.0)
The result of (sqrt 9) may be either 3 or 3.0, depending on the implementation.
The result of (sqrt -9) may be either #c(0 3) or #c(0.0 3.0).
[change_begin]
X3J13 voted in January 1989 (IEEE-ATAN-BRANCH-CUT) to specify certain
floating-point behavior when minus zero is supported. As a part of that vote it
approved a mathematical definition of complex square root in terms of complex
logarithm and exponential functions as
Square root
This specifies the branch cuts precisely whether minus zero is supported or
not; see phase and atan.
[change_end]
[Function]
isqrt integer
Integer square root: the argument must be a non-negative integer, and the
result is the greatest integer less than or equal to the exact positive square
root of the argument. For example:
(isqrt 9) => 3
(isqrt 12) => 3
(isqrt 300) => 17
(isqrt 325) => 18
-------------------------------------------------------------------------------
12.5.2. Trigonometric and Related Functions
Some of the functions in this section, such as abs and signum, are apparently
unrelated to trigonometric functions when considered as functions of real
numbers only. The way in which they are extended to operate on complex numbers
makes the trigonometric connection clear.
[Function]
abs number
Returns the absolute value of the argument. For a non-complex number x,
(abs x) == (if (minusp x) (- x) x)
and the result is always of the same type as the argument.
For a complex number z, the absolute value may be computed as
(sqrt (+ (expt (realpart z) 2) (expt (imagpart z) 2)))
-------------------------------------------------------------------------------
Implementation note: The careful implementor will not use this formula directly
for all complex numbers but will instead handle very large or very small
components specially to avoid intermediate overflow or underflow.
-------------------------------------------------------------------------------
For example:
(abs #c(3.0 -4.0)) => 5.0
The result of (abs #c(3 4)) may be either 5 or 5.0, depending on the
implementation.
[Function]
phase number
The phase of a number is the angle part of its polar representation as a
complex number. That is,
(phase z) == (atan (imagpart z) (realpart z))
[old_change_begin]
The result is in radians, in the range -pi (exclusive) to +pi (inclusive). The
phase of a positive non-complex number is zero; that of a negative non-complex
number is pi. The phase of zero is arbitrarily defined to be zero.
[old_change_end]
[change_begin]
X3J13 voted in January 1989 (IEEE-ATAN-BRANCH-CUT) to specify certain
floating-point behavior when minus zero is supported; phase is still defined in
terms of atan as above, but thanks to a change in atan the range of phase
becomes -pi inclusive to +pi inclusive. The value - results from an argument
whose real part is negative and whose imaginary part is minus zero. The phase
function therefore has a branch cut along the negative real axis. The phase of
+0+0i is +0, of +0-0i is -0, of -0+0i is +pi, and of -0-0i is -pi.
[change_end]
If the argument is a complex floating-point number, the result is a
floating-point number of the same type as the components of the argument. If
the argument is a floating-point number, the result is a floating-point number
of the same type. If the argument is a rational number or complex rational
number, the result is a single-format floating-point number.
[Function]
signum number
By definition,
(signum x) == (if (zerop x) x (/ x (abs x)))
For a rational number, signum will return one of -1, 0, or 1 according to
whether the number is negative, zero, or positive. For a floating-point number,
the result will be a floating-point number of the same format whose value is
-1, 0, or 1. For a complex number z, (signum z) is a complex number of the same
phase but with unit magnitude, unless z is a complex zero, in which case the
result is z. For example:
(signum 0) => 0
(signum -3.7L5) => -1.0L0
(signum 4/5) => 1
(signum #C(7.5 10.0)) => #C(0.6 0.8)
(signum #C(0.0 -14.7)) => #C(0.0 -1.0)
For non-complex rational numbers, signum is a rational function, but it may be
irrational for complex arguments.
[Function]
sin radians
cos radians
tan radians
sin returns the sine of the argument, cos the cosine, and tan the tangent. The
argument is in radians. The argument may be complex.
[Function]
cis radians
This computes . The name cis means ``cos + i sin,'' because . The argument
is in radians and may be any non-complex number. The result is a complex number
whose real part is the cosine of the argument and whose imaginary part is the
sine. Put another way, the result is a complex number whose phase is the equal
to the argument (mod 2) and whose magnitude is unity.
-------------------------------------------------------------------------------
Implementation note: Often it is cheaper to calculate the sine and cosine of a
single angle together than to perform two disjoint calculations.
-------------------------------------------------------------------------------
[Function]
asin number
acos number
asin returns the arc sine of the argument, and acos the arc cosine. The result
is in radians. The argument may be complex.
The arc sine and arc cosine functions may be defined mathematically for an
argument z as follows:
Arc sine
Arc cosine
Note that the result of asin or acos may be complex even if the argument is not
complex; this occurs when the absolute value of the argument is greater than 1.
[change_begin]
Kahan [25] suggests for acos the defining formula
Arc cosine
or even the much simpler . Both equations are mathematically equivalent to
the formula shown above.
[change_end]
-------------------------------------------------------------------------------
Implementation note: These formulae are mathematically correct, assuming
completely accurate computation. They may be terrible methods for
floating-point computation. Implementors should consult a good text on
numerical analysis. The formulae given above are not necessarily the simplest
ones for real-valued computations, either; they are chosen to define the branch
cuts in desirable ways for the complex case.
-------------------------------------------------------------------------------
[Function]
atan y &optional x
An arc tangent is calculated and the result is returned in radians.
With two arguments y and x, neither argument may be complex. The result is the
arc tangent of the quantity y/x. The signs of y and x are used to derive
quadrant information; moreover, x may be zero provided y is not zero. The value
of atan is always between -pi (exclusive) and +pi (inclusive). The following
table details various special cases.
[change_begin]
X3J13 voted in January 1989 (IEEE-ATAN-BRANCH-CUT) to specify certain
floating-point behavior when minus zero is supported. When there is a minus
zero, the preceding table must be modified slightly:
Note that the case y=0,x=0 is an error in the absence of minus zero, but the
four cases y=0,x=0 are defined in the presence of minus zero.
[change_end]
[old_change_begin]
With only one argument y, the argument may be complex. The result is the arc
tangent of y, which may be defined by the following formula:
Arc tangent
[old_change_end]
-------------------------------------------------------------------------------
Implementation note: This formula is mathematically correct, assuming
completely accurate computation. It may be a terrible method for floating-point
computation. Implementors should consult a good text on numerical analysis. The
formula given above is not necessarily the simplest one for real-valued
computations, either; it is chosen to define the branch cuts in desirable ways
for the complex case.
-------------------------------------------------------------------------------
[change_begin]
X3J13 voted in January 1989 (COMPLEX-ATAN-BRANCH-CUT) to replace the
preceding formula with the formula
log(1+iy) - log(1-iy)
Arc tangent ---------------------
2i
This change alters the direction of continuity for the branch cuts, which
alters the result returned by atan only for arguments on the imaginary axis
that are of magnitude greater than 1. See section 12.5.3 for further details.
[change_end]
For a non-complex argument y, the result is non-complex and lies between and
(both exclusive).
-------------------------------------------------------------------------------
Compatibility note: MacLisp has a function called atan whose range is from 0 to
2. Almost every other programming language (ANSI Fortran, IBM PL/1, Interlisp)
has a two-argument arc tangent function with range -pi to +pi. Lisp Machine
Lisp provides two two-argument arc tangent functions, atan (compatible with
MacLisp) and atan2 (compatible with all others).
Common Lisp makes two-argument atan the standard one with range -pi to +pi.
Observe that this makes the one-argument and two-argument versions of atan
compatible in the sense that the branch cuts do not fall in different places.
The Interlisp one-argument function arctan has a range from 0 to pi, while
nearly every other programming language provides the range to for
one-argument arc tangent! Nevertheless, since Interlisp uses the standard
two-argument version of arc tangent, its branch cuts are inconsistent anyway.
-------------------------------------------------------------------------------
[Constant]
pi
This global variable has as its value the best possible approximation to pi in
long floating-point format. For example:
(defun sind (x) ;The argument is in degrees
(sin (* x (/ (float pi x) 180))))
An approximation to pi in some other precision can be obtained by writing
(float pi x), where x is a floating-point number of the desired precision, or
by writing (coerce pi type), where type is the name of the desired type, such
as short-float.
[Function]
sinh number
cosh number
tanh number
asinh number
acosh number
atanh number
[old_change_begin]
These functions compute the hyperbolic sine, cosine, tangent, arc sine, arc
cosine, and arc tangent functions, which are mathematically defined for an
argument z as follows:
Hyperbolic sine
Hyperbolic cosine
Hyperbolic tangent
Hyperbolic arc sine
Hyperbolic arc cosine
Hyperbolic arc tangent WRONG!
[old_change_end]
[change_begin]
WARNING! The formula shown above for hyperbolic arc tangent is incorrect. It is
not a matter of incorrect branch cuts; it simply does not compute anything like
a hyperbolic arc tangent. This unfortunate error in the first edition was the
result of mistranscribing a (correct) APL formula from Penfield's paper [36].
The formula should have been transcribed as
Hyperbolic arc tangent
A proposal was submitted to X3J13 in September 1989 to replace the formulae for
acosh and atanh. See section 12.5.3 for further discussion.
[change_end]
Note that the result of acosh may be complex even if the argument is not
complex; this occurs when the argument is less than 1. Also, the result of
atanh may be complex even if the argument is not complex; this occurs when the
absolute value of the argument is greater than 1.
-------------------------------------------------------------------------------
Implementation note: These formulae are mathematically correct, assuming
completely accurate computation. They may be terrible methods for
floating-point computation. Implementors should consult a good text on
numerical analysis. The formulae given above are not necessarily the simplest
ones for real-valued computations, either; they are chosen to define the branch
cuts in desirable ways for the complex case.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
12.5.3. Branch Cuts, Principal Values, and Boundary Conditions in the Complex
Plane
Many of the irrational and transcendental functions are multiply defined in the
complex domain; for example, there are in general an infinite number of complex
values for the logarithm function. In each such case, a principal value must be
chosen for the function to return. In general, such values cannot be chosen so
as to make the range continuous; lines in the domain called branch cuts must be
defined, which in turn define the discontinuities in the range.
Common Lisp defines the branch cuts, principal values, and boundary conditions
for the complex functions following a proposal for complex functions in APL
[36]. The contents of this section are borrowed largely from that proposal.
-------------------------------------------------------------------------------
Compatibility note: The branch cuts defined here differ in a few very minor
respects from those advanced by W. Kahan, who considers not only the ``usual''
definitions but also the special modifications necessary for IEEE proposed
floating-point arithmetic, which has infinities and minus zero as explicit
computational objects. For example, he proposes that SQRT(-4+0i)=2i, but
SQRT(-4-0i)=-2i.
It may be that the differences between the APL proposal and Kahan's proposal
will be ironed out. If so, Common Lisp may be changed as necessary to be
compatible with these other groups. Any changes from the specification below
are likely to be quite minor, probably concerning primarily questions of which
side of a branch cut is continuous with the cut itself.
-------------------------------------------------------------------------------
[change_begin]
Indeed, X3J13 voted in January 1989 (COMPLEX-ATAN-BRANCH-CUT) to alter the
direction of continuity for the branch cuts of atan, and also
(IEEE-ATAN-BRANCH-CUT) to address the treatment of branch cuts in
implementations that have a distinct floating-point minus zero.
The treatment of minus zero centers in two-argument atan. If there is no minus
zero, then the branch cut runs just below the negative real axis as before, and
the range of two-argument atan is . If there is a minus zero, however, then
the branch cut runs precisely on the negative real axis, skittering between
pairs of numbers of the form -x+/-0i, and the range of two-argument atan is .
The treatment of minus zero by all other irrational and transcendental
functions is then specified by defining those functions in terms of
two-argument atan. First, phase is defined in terms of two-argument atan, and
complex abs in terms of real sqrt; then complex log is defined in terms of
phase, abs, and real log; then complex sqrt in terms of complex log; and
finally all others are defined in terms of these.
Kahan [25] treats these matters in some detail and also suggests specific
algorithms for implementing irrational and transcendental functions in IEEE
standard floating-point arithmetic [23].
Remarks in the first edition about the direction of the continuity of branch
cuts continue to hold in the absence of minus zero and may be ignored if minus
zero is supported; since all branch cuts happen to run along the principal
axes, they run between plus zero and minus zero, and so each sort of zero is
associated with the obvious quadrant.
[change_end]
sqrt
The branch cut for square root lies along the negative real axis,
continuous with quadrant II. The range consists of the right half-plane,
including the non-negative imaginary axis and excluding the negative
imaginary axis.
[change_begin]
X3J13 voted in January 1989 (IEEE-ATAN-BRANCH-CUT) to specify certain
floating-point behavior when minus zero is supported. As a part of that
vote it approved a mathematical definition of complex square root:
This defines the branch cuts precisely, whether minus zero is supported or
not.
[change_end]
phase
The branch cut for the phase function lies along the negative real axis,
continuous with quadrant II. The range consists of that portion of the
real axis between -pi (exclusive) and pi (inclusive).
[change_begin]
X3J13 voted in January 1989 (IEEE-ATAN-BRANCH-CUT) to specify certain
floating-point behavior when minus zero is supported. As a part of that
vote it approved a mathematical definition of phase:
where Fz is the imaginary part of z and Rz the real part of z. This
defines the branch cuts precisely, whether minus zero is supported or not.
[change_end]
log The branch cut for the logarithm function of one argument (natural
logarithm) lies along the negative real axis, continuous with quadrant II.
The domain excludes the origin. For a complex number z, z is defined to be
log z = (log|z|) + i(phase z)
Therefore the range of the one-argument logarithm function is that strip
of the complex plane containing numbers with imaginary parts between -pi
(exclusive) and pi (inclusive).
[change_begin]
The X3J13 vote on minus zero (IEEE-ATAN-BRANCH-CUT) would alter that
exclusive bound of -pi to be inclusive if minus zero is supported.
[change_end]
The two-argument logarithm function is defined as . This defines the
principal values precisely. The range of the two-argument logarithm
function is the entire complex plane. It is an error if z is zero. If z is
non-zero and b is zero, the logarithm is taken to be zero.
exp The simple exponential function has no branch cut.
expt
The two-argument exponential function is defined as . This defines the
principal values precisely. The range of the two-argument exponential
function is the entire complex plane. Regarded as a function of x, with b
fixed, there is no branch cut. Regarded as a function of b, with x fixed,
there is in general a branch cut along the negative real axis, continuous
with quadrant II. The domain excludes the origin. By definition, . If
b=0 and the real part of x is strictly positive, then . For all other
values of x, is an error.
asin
The following definition for arc sine determines the range and branch
cuts:
This is equivalent to the formula
recommended by Kahan [25].
The branch cut for the arc sine function is in two pieces: one along the
negative real axis to the left of -1 (inclusive), continuous with quadrant
II, and one along the positive real axis to the right of 1 (inclusive),
continuous with quadrant IV. The range is that strip of the complex plane
containing numbers whose real part is between and . A number with
real part equal to is in the range if and only if its imaginary part is
non-negative; a number with real part equal to is in the range if and
only if its imaginary part is non-positive.
acos
The following definition for arc cosine determines the range and branch
cuts:
or, which is equivalent,
The branch cut for the arc cosine function is in two pieces: one along the
negative real axis to the left of -1 (inclusive), continuous with quadrant
II, and one along the positive real axis to the right of 1 (inclusive),
continuous with quadrant IV. This is the same branch cut as for arc sine.
The range is that strip of the complex plane containing numbers whose real
part is between zero and pi. A number with real part equal to zero is in
the range if and only if its imaginary part is non-negative; a number with
real part equal to pi is in the range if and only if its imaginary part is
non-positive.
atan
The following definition for (one-argument) arc tangent determines the
range and branch cuts:
[old_change_begin]
Beware of simplifying this formula; ``obvious'' simplifications are likely
to alter the branch cuts or the values on the branch cuts incorrectly.
The branch cut for the arc tangent function is in two pieces: one along
the positive imaginary axis above i (exclusive), continuous with quadrant
II, and one along the negative imaginary axis below -i (exclusive),
continuous with quadrant IV. The points i and -i are excluded from the
domain. The range is that strip of the complex plane containing numbers
whose real part is between and . A number with real part equal to
is in the range if and only if its imaginary part is strictly positive; a
number with real part equal to is in the range if and only if its
imaginary part is strictly negative. Thus the range of the arc tangent
function is identical to that of the arc sine function with the points
and excluded.
[old_change_end]
[change_begin]
X3J13 voted in January 1989 (COMPLEX-ATAN-BRANCH-CUT) to replace the
formula shown above with the formula
This is equivalent to the formula
recommended by Kahan [25]. It causes the upper branch cut to be continuous
with quadrant I rather than quadrant II, and the lower branch cut to be
continuous with quadrant III rather than quadrant IV; otherwise it agrees
with the formula of the first edition. Therefore this change alters the
result returned by atan only for arguments on the positive imaginary axis
that are of magnitude greater than 1. The full description for this new
formula is as follows.
The branch cut for the arc tangent function is in two pieces: one along
the positive imaginary axis above i (exclusive), continuous with quadrant
I, and one along the negative imaginary axis below -i (exclusive),
continuous with quadrant III. The points i and -i are excluded from the
domain. The range is that strip of the complex plane containing numbers
whose real part is between and . A number with real part equal to
is in the range if and only if its imaginary part is strictly negative; a
number with real part equal to is in the range if and only if its
imaginary part is strictly positive. Thus the range of the arc tangent
function is not identical to that of the arc sine function.
[change_end]
asinh
The following definition for the inverse hyperbolic sine determines the
range and branch cuts:
The branch cut for the inverse hyperbolic sine function is in two pieces:
one along the positive imaginary axis above i (inclusive), continuous with
quadrant I, and one along the negative imaginary axis below -i
(inclusive), continuous with quadrant III. The range is that strip of the
complex plane containing numbers whose imaginary part is between and
. A number with imaginary part equal to is in the range if and only
if its real part is non-positive; a number with imaginary part equal to
is in the range if and only if its real part is non-negative.
acosh
The following definition for the inverse hyperbolic cosine determines the
range and branch cuts:
[change_begin]
Kahan [25] suggests the formula
pointing out that it yields the same principal value but eliminates a
gratuitous removable singularity at z=-1. A proposal was submitted to
X3J13 in September 1989 to replace the formula acosh with that recommended
by Kahan. There is a good possibility that it will be adopted.
[change_end]
The branch cut for the inverse hyperbolic cosine function lies along the
real axis to the left of 1 (inclusive), extending indefinitely along the
negative real axis, continuous with quadrant II and (between 0 and 1) with
quadrant I. The range is that half-strip of the complex plane containing
numbers whose real part is non-negative and whose imaginary part is
between -pi (exclusive) and pi (inclusive). A number with real part zero
is in the range if its imaginary part is between zero (inclusive) and pi
(inclusive).
atanh
The following definition for the inverse hyperbolic tangent determines the
range and branch cuts:
[old_change_begin]
WRONG!
[old_change_end]
[change_begin]
WARNING! The formula shown above for hyperbolic arc tangent is incorrect.
It is not a matter of incorrect branch cuts; it simply does not compute
anything like a hyperbolic arc tangent. This unfortunate error in the
first edition was the result of mistranscribing a (correct) APL formula
from Penfield's paper [36]. The formula should have been transcribed as
[change_end]
[old_change_begin]
Beware of simplifying this formula; ``obvious'' simplifications are likely
to alter the branch cuts or the values on the branch cuts incorrectly.
The branch cut for the inverse hyperbolic tangent function is in two
pieces: one along the negative real axis to the left of -1 (inclusive),
continuous with quadrant III, and one along the positive real axis to the
right of 1 (inclusive), continuous with quadrant I. The points -1 and 1
are excluded from the domain. The range is that strip of the complex plane
containing numbers whose imaginary part is between and . A number
with imaginary part equal to is in the range if and only if its real
part is strictly negative; a number with imaginary part equal to is in
the range if and only if its real part is strictly positive. Thus the
range of the inverse hyperbolic tangent function is identical to that of
the inverse hyperbolic sine function with the points and excluded.
[old_change_end]
[change_begin]
A proposal was submitted to X3J13 in September 1989 to replace the formula
atanh with that recommended by Kahan [25]:
There is a good possibility that it will be adopted. If it is, the
complete description of the branch cuts of atanh will then be as follows.
The branch cut for the inverse hyperbolic tangent function is in two
pieces: one along the negative real axis to the left of -1 (inclusive),
continuous with quadrant II, and one along the positive real axis to the
right of 1 (inclusive), continuous with quadrant IV. The points -1 and 1
are excluded from the domain. The range is that strip of the complex plane
containing numbers whose imaginary part is between and . A number
with imaginary part equal to is in the range if and only if its real
part is strictly positive; a number with imaginary part equal to is in
the range if and only if its real part is strictly negative. Thus the
range of the inverse hyperbolic tangent function is not the same as that
of the inverse hyperbolic sine function.
[change_end]
With these definitions, the following useful identities are obeyed throughout
the applicable portion of the complex domain, even on the branch cuts:
sin iz = i sinh z sinh iz = i sin z arctan iz = i arctanh z
cos iz = cosh z cosh iz = cos z arcsinh iz = i arcsin z
tan iz = i tanh z arcsin iz = i arcsinh z arctanh iz = i arctan z
[change_begin]
I thought it would be useful to provide some graphs illustrating the behavior
of the irrational and transcendental functions in the complex plane. It also
provides an opportunity to show off the Common Lisp code that was used to
generate them.
Imagine the complex plane to be decorated as follows. The real and imaginary
axes are painted with thick lines. Parallels from the axes on both sides at
distances of 1, 2, and 3 are painted with thin lines; these parallels are
doubly infinite lines, as are the axes. Four annuli (rings) are painted in
gradated shades of gray. Ring 1, the inner ring, consists of points whose
radial distances from the origin lie in the range [1/4, 1/2]; ring 2 is in the
radial range [3/4, 1]; ring 3, in the range [pi/2, 2]; and ring 4, in the range
[3, pi]. Ring j is divided into equal sectors, with each sector painted a
different shade of gray, darkening as one proceeds counterclockwise from the
positive real axis.
We can illustrate the behavior of a numerical function f by considering how it
maps the complex plane to itself. More specifically, consider each point z of
the decorated plane. We decorate a new plane by coloring the point f(z) with
the same color that point z had in the original decorated plane. In other
words, the newly decorated plane illustrates how the f maps the axes, other
horizontal and vertical lines, and annuli.
In each figure we will show only a fragment of the complex plane, with the real
axis horizontal in the usual manner (-pi to the left, +pi to the right) and the
imaginary axis vertical (-i below, +pii above). Each fragment shows a region
containing points whose real and imaginary parts are in the range [-4.1, 4.1].
The axes of the new plane are shown as very thin lines, with large tick marks
at integer coordinates and somewhat smaller tick marks at multiples of .
Figure 12-1 shows the result of plotting the identity function (quite
literally); the graph exhibits the decoration of the original plane.
Figures 12-2 through 12-20 show the graphs for the functions sqrt, exp, log,
sin, asin, cos, acos, tan, atan, sinh, asinh, cosh, acosh, tanh, and atanh, and
as a bonus, the graphs for the functions , , , and . All of these are
related to the trigonometric functions in various ways. For example, if ,
then , and if , then . It is instructive to examine the graph for and
try to visualize how it transforms the graph for sin into the graph for cos.
Each figure is accompanied by a commentary on what maps to what and other
interesting features. None of this material is terribly new; much of it may be
found in any good textbook on complex analysis. I believe that the particular
form in which the graphs are presented is novel, as well as the fact that the
graphs have been generated as PostScript [1] code by Common Lisp code. This
PostScript code was then fed directly to the typesetting equipment that set the
pages for this book. Samples of this PostScript code follow the figures
themselves, after which the code for the entire program is presented.
In the commentaries that accompany the figures I sometimes speak of mapping the
points +/- infinity or +/- infinity i. When I say that function f maps
+infinity to a certain point z, I mean that
Similarly, when I say that f maps -i to z, I mean that
In other words, I am considering a limit as one travels out along one of the
main axes. I also speak in a similar manner of mapping to one of these
infinities.
-------------------------------------------------------------------------------
* Identity Plot
* Square Root Function
* Exponential Function
* Natural Logarithm Function
* Function (z-1)/(z+1)
* Function (1+z)/(1-z)
* Sine Function
* Arc Sine Function
* Cosine Function
* Arc Cosine Function
* Tanget Function
* Arc Tangent Function
* Hyperbolic Sine Function
* Hyperbolic Arc Sine Function
* Hyperbolic Cosine Function
* Hyperbolic Arc Cosine Function
* Hyperbolic Tangent Function
* Hyperbolic Arc Tangent Function
* SQRT(1 - SQR(z))
* SQRT(1 + SQR(z))
Here is a sample of the PostScript code that generated figure 12-1, showing the
initial scaling, translation, and clipping parameters; the code for one sector
of the innermost annulus; and the code for the negative imaginary axis. Comment
lines indicate how path or boundary segments were generated separately and then
spliced (in order to allow for the places that a singularity might lurk, in
which case the generating code can ``inch up'' to the problematical argument
value).
The size of the entire PostScript file for the identity function was about 68
kilobytes (2757 lines, including comments). The smallest files were the plots
for atan and atanh, about 65 kilobytes apiece; the largest were the plots for
sin, cos, sinh, and cosh, about 138 kilobytes apiece.
% PostScript file for plot of function IDENTITY
% Plot is to fit in a region 4.666666666666667 inches square
% showing axes extending 4.1 units from the origin.
40.97560975609756 40.97560975609756 scale
4.1 4.1 translate
newpath
-4.1 -4.1 moveto
4.1 -4.1 lineto
4.1 4.1 lineto
-4.1 4.1 lineto
closepath
clip
% Moby grid for function IDENTITY
% Annulus 0.25 0.5 4 0.97 0.45
% Sector from 4.7124 to 6.2832 (quadrant 3)
newpath
0.0 -0.25 moveto
0.0 -0.375 lineto
%middle radial
0.0 -0.375 lineto
0.0 -0.5 lineto
%end radial
0.0 -0.5 lineto
0.092 -0.4915 lineto
0.1843 -0.4648 lineto
0.273 -0.4189 lineto
0.3536 -0.3536 lineto
%middle circumferential
0.3536 -0.3536 lineto
0.413 -0.2818 lineto
0.4594 -0.1974 lineto
0.4894 -0.1024 lineto
0.5 0.0 lineto
%end circumferential
0.5 0.0 lineto
0.375 0.0 lineto
%middle radial
0.375 0.0 lineto
0.25 0.0 lineto
%end radial
0.25 0.0 lineto
0.2297 -0.0987 lineto
0.1768 -0.1768 lineto
%middle circumferential
0.1768 -0.1768 lineto
0.0922 -0.2324 lineto
0.0 -0.25 lineto
%end circumferential
closepath
currentgray 0.45 setgray fill setgray
[2598 lines omitted]
% Vertical line from (0.0, -0.5) to (0.0, 0.0)
newpath
0.0 -0.5 moveto
0.0 0.0 lineto
0.05 setlinewidth 1 setlinecap stroke
% Vertical line from (0.0, -0.5) to (0.0, -1.0)
newpath
0.0 -0.5 moveto
0.0 -1.0 lineto
0.05 setlinewidth 1 setlinecap stroke
% Vertical line from (0.0, -2.0) to (0.0, -1.0)
newpath
0.0 -2.0 moveto
0.0 -1.0 lineto
0.05 setlinewidth 1 setlinecap stroke
% Vertical line from (0.0, -2.0) to (0.0, -1.1579208923731617E77)
newpath
0.0 -2.0 moveto
0.0 -6.3553 lineto
0.0 -6.378103166302659 lineto
0.0 -6.378103166302659 lineto
0.0 -6.378103166302659 lineto
0.05 setlinewidth 1 setlinecap stroke
[84 lines omitted]
% End of PostScript file for plot of function IDENTITY
Here is the program that generated the PostScript code for the graphs shown in
figures 12-1 through 12-20. It contains a mixture of fairly general mechanisms
and ad hoc kludges for plotting functions of a single complex argument while
gracefully handling extremely large and small values, branch cuts,
singularities, and periodic behavior. The aim was to provide a simple user
interface that would not require the caller to provide special advice for each
function to be plotted. The file for figure 12-1, for example, was generated by
the call (picture 'identity), which resulted in the writing of a file named
identity-plot.ps.
The program assumes that any periodic behavior will have a period that is a
multiple of 2pi; that branch cuts will fall along the real or imaginary axis;
and that singularities or very large or small values will occur only at the
origin, at 1 or +/-i, or on the boundaries of the annuli (particularly those
with radius or pi). The central function is parametric-path, which accepts
four arguments: two real numbers that are the endpoints of an interval of real
numbers, a function that maps this interval into a path in the complex plane,
and the function to be plotted; the task of parametric-path is to generate
PostScript code (a series of lineto operations) that will plot an approximation
to the image of the parametric path as transformed by the function to be
plotted. Each of the functions hline, vline, -hline, -vline, radial, and
circumferential takes appropriate parameters and returns a function suitable
for use as the third argument to parametric-path. There is some code that
defends against errors (by using ignore-errors) and against certain
peculiarities of IEEE floating-point arithmetic (the code that checks for
not-a-number (NaN) results).
The program is offered here without further comment or apology.
-------------------------------------------------------------------------------
(defparameter units-to-show 4.1)
(defparameter text-width-in-picas 28.0)
(defparameter device-pixels-per-inch 300)
(defparameter pixels-per-unit
(* (/ (/ text-width-in-picas 6)
(* units-to-show 2))
device-pixels-per-inch))
(defparameter big (sqrt (sqrt most-positive-single-float)))
(defparameter tiny (sqrt (sqrt least-positive-single-float)))
(defparameter path-really-losing 1000.0)
(defparameter path-outer-limit (* units-to-show (sqrt 2) 1.1))
(defparameter path-minimal-delta (/ 10 pixels-per-unit))
(defparameter path-outer-delta (* path-outer-limit 0.3))
(defparameter path-relative-closeness 0.00001)
(defparameter back-off-delta 0.0005)
(defun comment-line (stream &rest stuff)
(format stream "~%% ")
(apply #'format stream stuff)
(format t "~%% ")
(apply #'format t stuff))
(defun parametric-path (from to paramfn plotfn)
(assert (and (plusp from) (plusp to)))
(flet ((domainval (x) (funcall paramfn x))
(rangeval (x) (funcall plotfn (funcall paramfn x)))
(losing (x) (or (null x)
(/= (realpart x) (realpart x)) ;NaN?
(/= (imagpart x) (imagpart x)) ;NaN?
(> (abs (realpart x)) path-really-losing)
(> (abs (imagpart x)) path-really-losing))))
(when (> to 1000.0)
(let ((f0 (rangeval from))
(f1 (rangeval (+ from 1)))
(f2 (rangeval (+ from (* 2 pi))))
(f3 (rangeval (+ from 1 (* 2 pi))))
(f4 (rangeval (+ from (* 4 pi)))))
(flet ((close (x y)
(or (< (careful-abs (- x y)) path-minimal-delta)
(< (careful-abs (- x y))
(* (+ (careful-abs x) (careful-abs y))
path-relative-closeness)))))
(when (and (close f0 f2)
(close f2 f4)
(close f1 f3)
(or (and (close f0 f1)
(close f2 f3))
(and (not (close f0 f1))
(not (close f2 f3)))))
(format t "~&Periodicity detected.")
(setq to (+ from (* (signum (- to from)) 2 pi)))))))
(let ((fromrange (ignore-errors (rangeval from)))
(torange (ignore-errors (rangeval to))))
(if (losing fromrange)
(if (losing torange)
'()
(parametric-path (back-off from to) to paramfn plotfn))
(if (losing torange)
(parametric-path from (back-off to from) paramfn plotfn)
(expand-path (refine-path (list from to) #'rangeval)
#'rangeval))))))
(defun back-off (point other)
(if (or (> point 10.0) (< point 0.1))
(let ((sp (sqrt point)))
(if (or (> point sp other) (< point sp other))
sp
(* sp (sqrt other))))
(+ point (* (signum (- other point)) back-off-delta))))
(defun careful-abs (z)
(cond ((or (> (realpart z) big)
(< (realpart z) (- big))
(> (imagpart z) big)
(< (imagpart z) (- big)))
big)
((complexp z) (abs z))
((minusp z) (- z))
(t z)))
(defparameter max-refinements 5000)
(defun refine-path (original-path rangevalfn)
(flet ((rangeval (x) (funcall rangevalfn x)))
(let ((path original-path))
(do ((j 0 (+ j 1)))
((null (rest path)))
(when (zerop (mod (+ j 1) max-refinements))
(break "Runaway path"))
(let* ((from (first path))
(to (second path))
(fromrange (rangeval from))
(torange (rangeval to))
(dist (careful-abs (- torange fromrange)))
(mid (* (sqrt from) (sqrt to)))
(midrange (rangeval mid)))
(cond ((or (and (far-out fromrange) (far-out torange))
(and (< dist path-minimal-delta)
(< (abs (- midrange fromrange))
path-minimal-delta)
;; Next test is intentionally asymmetric to
;; avoid problems with periodic functions.
(< (abs (- (rangeval (/ (+ to (* from 1.5))
2.5))
fromrange))
path-minimal-delta)))
(pop path))
((= mid from) (pop path))
((= mid to) (pop path))
(t (setf (rest path) (cons mid (rest path)))))))))
original-path)
(defun expand-path (path rangevalfn)
(flet ((rangeval (x) (funcall rangevalfn x)))
(let ((final-path (list (rangeval (first path)))))
(do ((p (rest path) (cdr p)))
((null p)
(unless (rest final-path)
(break "Singleton path"))
(reverse final-path))
(let ((v (rangeval (car p))))
(cond ((and (rest final-path)
(not (far-out v))
(not (far-out (first final-path)))
(between v (first final-path)
(second final-path)))
(setf (first final-path) v))
((null (rest p)) ;Mustn't omit last point
(push v final-path))
((< (abs (- v (first final-path))) path-minimal-delta))
((far-out v)
(unless (and (far-out (first final-path))
(< (abs (- v (first final-path)))
path-outer-delta))
(push (* 1.01 path-outer-limit (signum v))
final-path)))
(t (push v final-path))))))))
(defun far-out (x)
(> (careful-abs x) path-outer-limit))
(defparameter between-tolerance 0.000001)
(defun between (p q r)
(let ((px (realpart p)) (py (imagpart p))
(qx (realpart q)) (qy (imagpart q))
(rx (realpart r)) (ry (imagpart r)))
(and (or (<= px qx rx) (>= px qx rx))
(or (<= py qy ry) (>= py qy ry))
(< (abs (- (* (- qx px) (- ry qy))
(* (- rx qx) (- qy py))))
between-tolerance))))
(defun circle (radius)
#'(lambda (angle) (* radius (cis angle))))
(defun hline (imag)
#'(lambda (real) (complex real imag)))
(defun vline (real)
#'(lambda (imag) (complex real imag)))
(defun -hline (imag)
#'(lambda (real) (complex (- real) imag)))
(defun -vline (real)
#'(lambda (imag) (complex real (- imag))))
(defun radial (phi quadrant)
#'(lambda (rho) (repair-quadrant (* rho (cis phi)) quadrant)))
(defun circumferential (rho quadrant)
#'(lambda (phi) (repair-quadrant (* rho (cis phi)) quadrant)))
;;; Quadrant is 0, 1, 2, or 3, meaning I, II, III, or IV.
(defun repair-quadrant (z quadrant)
(complex (* (+ (abs (realpart z)) tiny)
(case quadrant (0 1.0) (1 -1.0) (2 -1.0) (3 1.0)))
(* (+ (abs (imagpart z)) tiny)
(case quadrant (0 1.0) (1 1.0) (2 -1.0) (3 -1.0)))))
(defun clamp-real (x)
(if (far-out x)
(* (signum x) path-outer-limit)
(round-real x)))
(defun round-real (x)
(/ (round (* x 10000.0)) 10000.0))
(defun round-point (z)
(complex (round-real (realpart z)) (round-real (imagpart z))))
(defparameter hiringshade 0.97)
(defparameter loringshade 0.45)
(defparameter ticklength 0.12)
(defparameter smallticklength 0.09)
;;; This determines the pattern of lines and annuli to be drawn.
(defun moby-grid (&optional (fn 'sqrt) (stream t))
(comment-line stream "Moby grid for function ~S" fn)
(shaded-annulus 0.25 0.5 4 hiringshade loringshade fn stream)
(shaded-annulus 0.75 1.0 8 hiringshade loringshade fn stream)
(shaded-annulus (/ pi 2) 2.0 16 hiringshade loringshade fn stream)
(shaded-annulus 3 pi 32 hiringshade loringshade fn stream)
(moby-lines :horizontal 1.0 fn stream)
(moby-lines :horizontal -1.0 fn stream)
(moby-lines :vertical 1.0 fn stream)
(moby-lines :vertical -1.0 fn stream)
(let ((tickline 0.015)
(axisline 0.008))
(flet ((tick (n) (straight-line (complex n ticklength)
(complex n (- ticklength))
tickline
stream))
(smalltick (n) (straight-line (complex n smallticklength)
(complex n (- smallticklength))
tickline
stream)))
(comment-line stream "Real axis")
(straight-line #c(-5 0) #c(5 0) axisline stream)
(dotimes (j (floor units-to-show))
(let ((q (+ j 1))) (tick q) (tick (- q))))
(dotimes (j (floor units-to-show (/ pi 2)))
(let ((q (* (/ pi 2) (+ j 1))))
(smalltick q)
(smalltick (- q)))))
(flet ((tick (n) (straight-line (complex ticklength n)
(complex (- ticklength) n)
tickline
stream))
(smalltick (n) (straight-line (complex smallticklength n)
(complex (- smallticklength) n)
tickline
stream)))
(comment-line stream "Imaginary axis")
(straight-line #c(0 -5) #c(0 5) axisline stream)
(dotimes (j (floor units-to-show))
(let ((q (+ j 1))) (tick q) (tick (- q))))
(dotimes (j (floor units-to-show (/ pi 2)))
(let ((q (* (/ pi 2) (+ j 1))))
(smalltick q)
(smalltick (- q)))))))
(defun straight-line (from to wid stream)
(format stream
"~%newpath ~S ~S moveto ~S ~S lineto ~S ~
setlinewidth 1 setlinecap stroke"
(realpart from)
(imagpart from)
(realpart to)
(imagpart to)
;;; This function draws the lines for the pattern.
(defun moby-lines (orientation signum plotfn stream)
(let ((paramfn (ecase orientation
(:horizontal (if (< signum 0) #'-hline #'hline))
(:vertical (if (< signum 0) #'-vline #'vline)))))
(flet ((foo (from to other wid)
(ecase orientation
(:horizontal
(comment-line stream
"Horizontal line from (~S, ~S) to (~S, ~S)"
(round-real (* signum from))
(round-real other)
(round-real (* signum to))
(round-real other)))
(:vertical
(comment-line stream
"Vertical line from (~S, ~S) to (~S, ~S)"
(round-real other)
(round-real (* signum from))
(round-real other)
(round-real (* signum to)))))
(postscript-path
stream
(parametric-path from
to
(funcall paramfn other)
plotfn))
(postscript-penstroke stream wid)))
(let* ((thick 0.05)
(thin 0.02))
;; Main axis
(foo 0.5 tiny 0.0 thick)
(foo 0.5 1.0 0.0 thick)
(foo 2.0 1.0 0.0 thick)
(foo 2.0 big 0.0 thick)
;; Parallels at 1 and -1
(foo 2.0 tiny 1.0 thin)
(foo 2.0 big 1.0 thin)
(foo 2.0 tiny -1.0 thin)
(foo 2.0 big -1.0 thin)
;; Parallels at 2, 3, -2, -3
(foo tiny big 2.0 thin)
(foo tiny big -2.0 thin)
(foo tiny big 3.0 thin)
(foo tiny big -3.0 thin)))))
(defun splice (p q)
(let ((v (car (last p)))
(w (first q)))
(and (far-out v)
(far-out w)
(>= (abs (- v w)) path-outer-delta)
;; Two far-apart far-out points. Try to walk around
;; outside the perimeter, in the shorter direction.
(let* ((pdiff (phase (/ v w)))
(npoints (floor (abs pdiff) (asin .2)))
(delta (/ pdiff (+ npoints 1)))
(incr (cis delta)))
(do ((j 0 (+ j 1))
(p (list w "end splice") (cons (* (car p) incr) p)))
;;; This function draws the annuli for the pattern.
(defun shaded-annulus (inner outer sectors firstshade lastshade fn stream)
(assert (zerop (mod sectors 4)))
(comment-line stream "Annulus ~S ~S ~S ~S ~S"
(round-real inner) (round-real outer)
sectors firstshade lastshade)
(dotimes (jj sectors)
(let ((j (- sectors jj 1)))
(let* ((lophase (+ tiny (* 2 pi (/ j sectors))))
(hiphase (* 2 pi (/ (+ j 1) sectors)))
(midphase (/ (+ lophase hiphase) 2.0))
(midradius (/ (+ inner outer) 2.0))
(quadrant (floor (* j 4) sectors)))
(comment-line stream "Sector from ~S to ~S (quadrant ~S)"
(round-real lophase)
(round-real hiphase)
quadrant)
(let ((p0 (reverse (parametric-path midradius
inner
(radial lophase quadrant)
fn)))
(p1 (parametric-path midradius
outer
(radial lophase quadrant)
fn))
(p2 (reverse (parametric-path midphase
lophase
(circumferential outer
quadrant)
fn)))
(p3 (parametric-path midphase
hiphase
(circumferential outer quadrant)
fn))
(p4 (reverse (parametric-path midradius
outer
(radial hiphase quadrant)
fn)))
(p5 (parametric-path midradius
inner
(radial hiphase quadrant)
fn))
(p6 (reverse (parametric-path midphase
hiphase
(circumferential inner
quadrant)
fn)))
(p7 (parametric-path midphase
lophase
(circumferential inner quadrant)
fn)))
(postscript-closed-path stream
(append
p0 (splice p0 p1) '("middle radial")
p1 (splice p1 p2) '("end radial")
p2 (splice p2 p3) '("middle circumferential")
p3 (splice p3 p4) '("end circumferential")
p4 (splice p4 p5) '("middle radial")
p5 (splice p5 p6) '("end radial")
p6 (splice p6 p7) '("middle circumferential")
p7 (splice p7 p0) '("end circumferential")
)))
(postscript-shade stream
(/ (+ (* firstshade (- (- sectors 1) j))
(* lastshade j))
(- sectors 1)))))))
(defun postscript-penstroke (stream wid)
(format stream "~%~S setlinewidth 1 setlinecap stroke"
wid))
(defun postscript-shade (stream shade)
(format stream "~%currentgray ~S setgray fill setgray"
shade))
(defun postscript-closed-path (stream path)
(unless (every #'far-out (remove-if-not #'numberp path))
(postscript-raw-path stream path)
(format stream "~% closepath")))
(defun postscript-path (stream path)
(unless (every #'far-out (remove-if-not #'numberp path))
(postscript-raw-path stream path)))
;;; Print a path as a series of PostScript "lineto" commands.
(defun postscript-raw-path (stream path)
(format stream "~%newpath")
(let ((fmt "~% ~S ~S moveto"))
(dolist (pt path)
(cond ((stringp pt)
(format stream "~% %~A" pt))
(t (format stream
fmt
(clamp-real (realpart pt))
(clamp-real (imagpart pt)))
(setq fmt "~% ~S ~S lineto"))))))
;;; Definitions of functions to be plotted that are not
;;; standard Common Lisp functions.
(defun one-plus-over-one-minus (x) (/ (+ 1 x) (- 1 x)))
(defun one-minus-over-one-plus (x) (/ (- 1 x) (+ 1 x)))
(defun sqrt-square-minus-one (x) (sqrt (- 1 (* x x))))
(defun sqrt-one-plus-square (x) (sqrt (+ 1 (* x x))))
;;; Because X3J13 voted for a new definition of the atan function,
;;; the following definition was used in place of the atan function
;;; provided by the Common Lisp implementation I was using.
(defun good-atan (x)
(/ (- (log (+ 1 (* x #c(0 1))))
(log (- 1 (* x #c(0 1)))))
#c(0 2)))
;;; Because the first edition had an erroneous definition of atanh,
;;; the following definition was used in place of the atanh function
;;; provided by the Common Lisp implementation I was using.
(defun really-good-atanh (x)
(/ (- (log (+ 1 x))
(log (- 1 x)))
;;; This is the main procedure that is intended to be called by a user.
(defun picture (&optional (fn #'sqrt))
(with-open-file (stream (concatenate 'string
(string-downcase (string fn))
"-plot.ps")
:direction :output)
(format stream "% PostScript file for plot of function ~S~%" fn)
(format stream "% Plot is to fit in a region ~S inches square~%"
(/ text-width-in-picas 6.0))
(format stream
"% showing axes extending ~S units from the origin.~%"
units-to-show)
(let ((scaling (/ (* text-width-in-picas 12) (* units-to-show 2))))
(format stream "~%~S ~:*~S scale" scaling))
(format stream "~%~S ~:*~S translate" units-to-show)
(format stream "~%newpath")
(format stream "~% ~S ~S moveto" (- units-to-show) (- units-to-show))
(format stream "~% ~S ~S lineto" units-to-show (- units-to-show))
(format stream "~% ~S ~S lineto" units-to-show units-to-show)
(format stream "~% ~S ~S lineto" (- units-to-show) units-to-show)
(format stream "~% closepath")
(format stream "~%clip")
(moby-grid fn stream)
(format stream
"~%% End of PostScript file for plot of function ~S"
fn)
(terpri stream)))
-------------------------------------------------------------------------------
12.6. Type Conversions and Component Extractions on Numbers
While most arithmetic functions will operate on any kind of number, coercing
types if necessary, the following functions are provided to allow specific
conversions of data types to be forced when desired.
[Function]
float number &optional other
This converts any non-complex number to a floating-point number. With no second
argument, if number is already a floating-point number, then number is
returned; otherwise a single-float is produced. If the argument other is
provided, then it must be a floating-point number, and number is converted to
the same format as other. See also coerce.
[Function]
rational number
rationalize number
Each of these functions converts any non-complex number to a rational number.
If the argument is already rational, it is returned. The two functions differ
in their treatment of floating-point numbers.
rational assumes that the floating-point number is completely accurate and
returns a rational number mathematically equal to the precise value of the
floating-point number.
rationalize assumes that the floating-point number is accurate only to the
precision of the floating-point representation and may return any rational
number for which the floating-point number is the best available approximation
of its format; in doing this it attempts to keep both numerator and denominator
small.
It is always the case that
(float (rational x) x) == x
and
(float (rationalize x) x) == x
That is, rationalizing a floating-point number by either method and then
converting it back to a floating-point number of the same format produces the
original number. What distinguishes the two functions is that rational
typically has a simple, inexpensive implementation, whereas rationalize goes to
more trouble to produce a result that is more pleasant to view and simpler to
compute with for some purposes.
[Function]
numerator rational
denominator rational
These functions take a rational number (an integer or ratio) and return as an
integer the numerator or denominator of the canonical reduced form of the
rational. The numerator of an integer is that integer; the denominator of an
integer is 1. Note that
(gcd (numerator x) (denominator x)) => 1
The denominator will always be a strictly positive integer; the numerator may
be any integer. For example:
(numerator (/ 8 -6)) => -4
(denominator (/ 8 -6)) => 3
There is no fix function in Common Lisp because there are several interesting
ways to convert non-integral values to integers. These are provided by the
functions below, which perform not only type conversion but also some
non-trivial calculations as well.
[Function]
floor number &optional divisor
ceiling number &optional divisor
truncate number &optional divisor
round number &optional divisor
In the simple one-argument case, each of these functions converts its argument
number (which must not be complex) to an integer. If the argument is already an
integer, it is returned directly. If the argument is a ratio or floating-point
number, the functions use different algorithms for the conversion.
floor converts its argument by truncating toward negative infinity; that is,
the result is the largest integer that is not larger than the argument.
ceiling converts its argument by truncating toward positive infinity; that is,
the result is the smallest integer that is not smaller than the argument.
truncate converts its argument by truncating toward zero; that is, the result
is the integer of the same sign as the argument and which has the greatest
integral magnitude not greater than that of the argument.
round converts its argument by rounding to the nearest integer; if number is
exactly halfway between two integers (that is, of the form integer+0.5), then
it is rounded to the one that is even (divisible by 2).
The following table shows what the four functions produce when given various
arguments.
Argument floor ceiling truncate round
----------------------------------------------------------
2.6 2 3 2 3
2.5 2 3 2 2
2.4 2 3 2 2
0.7 0 1 0 1
0.3 0 1 0 0
-0.3 -1 0 0 0
-0.7 -1 0 0 -1
-2.4 -3 -2 -2 -2
-2.5 -3 -2 -2 -2
-2.6 -3 -2 -2 -3
----------------------------------------------------------
If a second argument divisor is supplied, then the result is the appropriate
type of rounding or truncation applied to the result of dividing the number by
the divisor. For example, (floor 5 2) == (floor (/ 5 2)) but is potentially
more efficient.
[change_begin]
This statement is not entirely accurate; one should instead say that (values
(floor 5 2)) == (values (floor (/ 5 2))), because there is a second value to
consider, as discussed below. In other words, the first values returned by the
two forms will be the same, but in general the second values will differ.
Indeed, we have
(floor 5 2) => 2 and 1
(floor (/ 5 2)) => 2 and 1/2
for this example.
[change_end]
The divisor may be any non-complex number.
[change_begin]
It is generally accepted that it is an error for the divisor to be zero.
[change_end]
The one-argument case is exactly like the two-argument case where the second
argument is 1.
[change_begin]
In other words, the one-argument case returns an integer and fractional part
for the number: (truncate 5.3) => 5.0 and 0.3, for example.
[change_end]
Each of the functions actually returns two values, whether given one or two
arguments. The second result is the remainder and may be obtained using
multiple-value-bind and related constructs. If any of these functions is given
two arguments x and y and produces results q and r, then q y+r=x. The first
result q is always an integer. The remainder r is an integer if both arguments
are integers, is rational if both arguments are rational, and is floating-point
if either argument is floating-point. One consequence is that in the
one-argument case the remainder is always a number of the same type as the
argument.
When only one argument is given, the two results are exact; the mathematical
sum of the two results is always equal to the mathematical value of the
argument.
-------------------------------------------------------------------------------
Compatibility note: The names of the functions floor, ceiling, truncate, and
round are more accurate than names like fix that have heretofore been used in
various Lisp systems. The names used here are compatible with standard
mathematical terminology (and with PL/1, as it happens). In Fortran ifix means
truncate. Algol 68 provides round and uses entier to mean floor. In MacLisp,
fix and ifix both mean floor (one is generic, the other flonum-in/fixnum-out).
In Interlisp, fix means truncate. In Lisp Machine Lisp, fix means floor and
fixr means round. Standard Lisp provides a fix function but does not specify
precisely what it does. The existing usage of the name fix is so confused that
it seemed best to avoid it altogether.
The names and definitions given here have recently been adopted by Lisp Machine
Lisp, and MacLisp and NIL (New Implementation of Lisp) seem likely to follow
suit.
-------------------------------------------------------------------------------
[Function]
mod number divisor
rem number divisor
mod performs the operation floor on its two arguments and returns the second
result of floor as its only result. Similarly, rem performs the operation
truncate on its arguments and returns the second result of truncate as its only
result.
mod and rem are therefore the usual modulus and remainder functions when
applied to two integer arguments. In general, however, the arguments may be
integers or floating-point numbers.
(mod 13 4) => 1 (rem 13 4) => 1
(mod -13 4) => 3 (rem -13 4) => -1
(mod 13 -4) => -3 (rem 13 -4) => 1
(mod -13 -4) => -1 (rem -13 -4) => -1
(mod 13.4 1) => 0.4 (rem 13.4 1) => 0.4
(mod -13.4 1) => 0.6 (rem -13.4 1) => -0.4
-------------------------------------------------------------------------------
Compatibility note: The Interlisp function remainder is essentially equivalent
to the Common Lisp function rem. The MacLisp function remainder is like rem but
accepts only integer arguments.
-------------------------------------------------------------------------------
[Function]
ffloor number &optional divisor
fceiling number &optional divisor
ftruncate number &optional divisor
fround number &optional divisor
These functions are just like floor, ceiling, truncate, and round, except that
the result (the first result of two) is always a floating-point number rather
than an integer. It is roughly as if ffloor gave its arguments to floor, and
then applied float to the first result before passing them both back. In
practice, however, ffloor may be implemented much more efficiently. Similar
remarks apply to the other three functions. If the first argument is a
floating-point number, and the second argument is not a floating-point number
of longer format, then the first result will be a floating-point number of the
same type as the first argument. For example:
(ffloor -4.7) => -5.0 and 0.3
(ffloor 3.5d0) => 3.0d0 and 0.5d0
[Function]
decode-float float
scale-float float integer
float-radix float
float-sign float1 &optional float2
float-digits float
float-precision float
integer-decode-float float
The function decode-float takes a floating-point number and returns three
values.
The first value is a new floating-point number of the same format representing
the significand; the second value is an integer representing the exponent; and
the third value is a floating-point number of the same format indicating the
sign (-1.0 or 1.0). Let b be the radix for the floating-point representation;
then decode-float divides the argument by an integral power of b so as to bring
its value between 1/b (inclusive) and 1 (exclusive) and returns the quotient as
the first value. If the argument is zero, however, the result is equal to the
absolute value of the argument (that is, if there is a negative zero, its
significand is considered to be a positive zero).
The second value of decode-float is the integer exponent e to which b must be
raised to produce the appropriate power for the division. If the argument is
zero, any integer value may be returned, provided that the identity shown below
for scale-float holds.
The third value of decode-float is a floating-point number, of the same format
as the argument, whose absolute value is 1 and whose sign matches that of the
argument.
The function scale-float takes a floating-point number f (not necessarily
between 1/b and 1) and an integer k, and returns (* f (expt (float b f) k)).
(The use of scale-float may be much more efficient than using exponentiation
and multiplication and avoids intermediate overflow and underflow if the final
result is representable.)
Note that
(multiple-value-bind (signif expon sign)
(decode-float f)
(scale-float signif expon))
== (abs f)
and
(multiple-value-bind (signif expon sign)
(decode-float f)
(* (scale-float signif expon) sign))
== f
The function float-radix returns (as an integer) the radix b of the
floating-point argument.
The function float-sign returns a floating-point number z such that z and
float1 have the same sign and also such that z and float2 have the same
absolute value. The argument float2 defaults to the value of (float 1 float1);
(float-sign x) therefore always produces a 1.0 or -1.0 of appropriate format
according to the sign of x. (Note that if an implementation has distinct
representations for negative zero and positive zero, then (float-sign -0.0) =>
-1.0.)
The function float-digits returns, as a non-negative integer, the number of
radix-b digits used in the representation of its argument (including any
implicit digits, such as a ``hidden bit''). The function float-precision
returns, as a non-negative integer, the number of significant radix-b digits
present in the argument; if the argument is (a floating-point) zero, then the
result is (an integer) zero. For normalized floating-point numbers, the results
of float-digits and float-precision will be the same, but the precision will be
less than the number of representation digits for a denormalized or zero
number.
The function integer-decode-float is similar to decode-float but for its first
value returns, as an integer, the significand scaled so as to be an integer.
For an argument f, this integer will be strictly less than
(expt b (float-precision f))
but no less than
(expt b (- (float-precision f) 1))
except that if f is zero, then the integer value will be zero.
The second value bears the same relationship to the first value as for
decode-float:
(multiple-value-bind (signif expon sign)
(integer-decode-float f)
(scale-float (float signif f) expon))
== (abs f)
The third value of integer-decode-float will be 1 or -1.
-------------------------------------------------------------------------------
Rationale: These functions allow the writing of machine-independent, or at
least machine-parameterized, floating-point software of reasonable efficiency.
-------------------------------------------------------------------------------
[Function]
complex realpart &optional imagpart
The arguments must be non-complex numbers; a number is returned that has
realpart as its real part and imagpart as its imaginary part, possibly
converted according to the rule of floating-point contagion (thus both
components will be of the same type). If imagpart is not specified, then
(coerce 0 (type-of realpart)) is effectively used. Note that if both the
realpart and imagpart are rational and the imagpart is zero, then the result is
just the realpart because of the rule of canonical representation for complex
rationals. It follows that the result of complex is not always a complex
number; it may be simply a rational.
[Function]
realpart number
imagpart number
These return the real and imaginary parts of a complex number. If number is a
non-complex number, then realpart returns its argument number and imagpart
returns (* 0 number), which has the effect that the imaginary part of a
rational is 0 and that of a floating-point number is a floating-point zero of
the same format.
[change_begin]
A clever way to multiply a complex number z by i is to write
(complex (- (imagpart z)) (realpart z))
instead of (* z #c(0 1)). This cleverness is not always gratuitous; it may be
of particular importance in the presence of minus zero. For example, if we are
using IEEE standard floating-point arithmetic and z=4+0i, the result of the
clever expression is -0+4i, a true rotation of z, whereas the result of (* z
#c(0 1)) is likely to be
(4+0i)(+0+i) = ((4)(+0)-(+0)(1))+((4)(1)+(+0)(+0)i
= ((+0)-(+0))+((4)+(+0))i = +0+4i
which could land on the wrong side of a branch cut, for example.
[change_end]
-------------------------------------------------------------------------------
12.7. Logical Operations on Numbers
The logical operations in this section require integers as arguments; it is an
error to supply a non-integer as an argument. The functions all treat integers
as if they were represented in two's-complement notation.
-------------------------------------------------------------------------------
Implementation note: Internally, of course, an implementation of Common Lisp
may or may not use a two's-complement representation. All that is necessary is
that the logical operations perform calculations so as to give this appearance
to the user.
-------------------------------------------------------------------------------
The logical operations provide a convenient way to represent an infinite vector
of bits. Let such a conceptual vector be indexed by the non-negative integers.
Then bit j is assigned a ``weight'' . Assume that only a finite number of
bits are 1's or only a finite number of bits are 0's. A vector with only a
finite number of one-bits is represented as the sum of the weights of the
one-bits, a positive integer. A vector with only a finite number of zero-bits
is represented as -1 minus the sum of the weights of the zero-bits, a negative
integer.
This method of using integers to represent bit-vectors can in turn be used to
represent sets. Suppose that some (possibly countably infinite) universe of
discourse for sets is mapped into the non-negative integers. Then a set can be
represented as a bit vector; an element is in the set if the bit whose index
corresponds to that element is a one-bit. In this way all finite sets can be
represented (by positive integers), as well as all sets whose complements are
finite (by negative integers). The functions logior, logand, and logxor defined
below then compute the union, intersection, and symmetric difference operations
on sets represented in this way.
[Function]
logior &rest integers
This returns the bit-wise logical inclusive or of its arguments. If no argument
is given, then the result is zero, which is an identity for this operation.
[Function]
logxor &rest integers
This returns the bit-wise logical exclusive or of its arguments. If no argument
is given, then the result is zero, which is an identity for this operation.
[Function]
logand &rest integers
This returns the bit-wise logical and of its arguments. If no argument is
given, then the result is -1, which is an identity for this operation.
[Function]
logeqv &rest integers
This returns the bit-wise logical equivalence (also known as exclusive nor) of
its arguments. If no argument is given, then the result is -1, which is an
identity for this operation.
[Function]
lognand integer1 integer2
lognor integer1 integer2
logandc1 integer1 integer2
logandc2 integer1 integer2
logorc1 integer1 integer2
logorc2 integer1 integer2
These are the other six non-trivial bit-wise logical operations on two
arguments. Because they are not associative, they take exactly two arguments
rather than any non-negative number of arguments.
(lognand n1 n2) == (lognot (logand n1 n2))
(lognor n1 n2) == (lognot (logior n1 n2))
(logandc1 n1 n2) == (logand (lognot n1) n2)
(logandc2 n1 n2) == (logand n1 (lognot n2))
(logorc1 n1 n2) == (logior (lognot n1) n2)
(logorc2 n1 n2) == (logior n1 (lognot n2))
The ten bit-wise logical operations on two integers are summarized in the
following table:
----------------------------------------------------------------
integer1 0 0 1 1
integer2 0 1 0 1 Operation Name
----------------------------------------------------------------
logand 0 0 0 1 and
logior 0 1 1 1 inclusive or
logxor 0 1 1 0 exclusive or
logeqv 1 0 0 1 equivalence (exclusive nor)
lognand 1 1 1 0 not-and
lognor 1 0 0 0 not-or
logandc1 0 1 0 0 and complement of integer1 with integer2
logandc2 0 0 1 0 and integer1 with complement of integer2
logorc1 1 1 0 1 or complement of integer1 with integer2
logorc2 1 0 1 1 or integer1 with complement of integer2
[Function]
boole op integer1 integer2
[Constant]
boole-clr
boole-set
boole-1
boole-2
boole-c1
boole-c2
boole-and
boole-ior
boole-xor
boole-eqv
boole-nand
boole-nor
boole-andc1
boole-andc2
boole-orc1
boole-orc2
The function boole takes an operation op and two integers, and returns an
integer produced by performing the logical operation specified by op on the two
integers. The precise values of the sixteen constants are
implementation-dependent, but they are suitable for use as the first argument
to boole:
----------------------------------------------------------------
integer1 0 0 1 1
integer2 0 1 0 1 Operation Performed
----------------------------------------------------------------
boole-clr 0 0 0 0 always 0
boole-set 1 1 1 1 always 1
boole-1 0 0 1 1 integer1
boole-2 0 1 0 1 integer2
boole-c1 1 1 0 0 complement of integer1
boole-c2 1 0 1 0 complement of integer2
boole-and 0 0 0 1 and
boole-ior 0 1 1 1 inclusive or
boole-xor 0 1 1 0 exclusive or
boole-eqv 1 0 0 1 equivalence (exclusive nor)
boole-nand 1 1 1 0 not-and
boole-nor 1 0 0 0 not-or
boole-andc1 0 1 0 0 and complement of integer1 with integer2
boole-andc2 0 0 1 0 and integer1 with complement of integer2
boole-orc1 1 1 0 1 or complement of integer1 with integer2
boole-orc2 1 0 1 1 or integer1 with complement of integer2
boole can therefore compute all sixteen logical functions on two arguments. In
general,
(boole boole-and x y) == (logand x y)
and the latter is more perspicuous. However, boole is useful when it is
necessary to parameterize a procedure so that it can use one of several logical
operations.
[Function]
lognot integer
This returns the bit-wise logical not of its argument. Every bit of the result
is the complement of the corresponding bit in the argument.
(logbitp j (lognot x)) == (not (logbitp j x))
[Function]
logtest integer1 integer2
logtest is a predicate that is true if any of the bits designated by the 1's in
integer1 are 1's in integer2.
(logtest x y) == (not (zerop (logand x y)))
[Function]
logbitp index integer
logbitp is true if the bit in integer whose index is index (that is, its weight
is ) is a one-bit; otherwise it is false. For example:
(logbitp 2 6) is true
(logbitp 0 6) is false
(logbitp k n) == (ldb-test (byte 1 k) n)
[change_begin]
X3J13 voted in January 1989 (ARGUMENTS-UNDERSPECIFIED) to clarify that the
index must be a non-negative integer.
[change_end]
[Function]
ash integer count
This function shifts integer arithmetically left by count bit positions if
count is positive, or right by -count bit positions if count is negative. The
sign of the result is always the same as the sign of integer.
Mathematically speaking, this operation performs the computation ).
Logically, this moves all of the bits in integer to the left, adding zero-bits
at the bottom, or moves them to the right, discarding bits. (In this context
the question of what gets shifted in on the left is irrelevant; integers,
viewed as strings of bits, are ``half-infinite,'' that is, conceptually extend
infinitely far to the left.) For example:
(logbitp j (ash n k)) == (and (>= j k) (logbitp (- j k) n))
[Function]
logcount integer
The number of bits in integer is determined and returned. If integer is
positive, the 1-bits in its binary representation are counted. If integer is
negative, the 0-bits in its two's-complement binary representation are counted.
The result is always a non-negative integer. For example:
(logcount 13) => 3 ;Binary representation is ...0001101
(logcount -13) => 2 ;Binary representation is ...1110011
(logcount 30) => 4 ;Binary representation is ...0011110
(logcount -30) => 4 ;Binary representation is ...1100010
The following identity always holds:
(logcount x) == (logcount (- (+ x 1)))
== (logcount (lognot x))
[Function]
integer-length integer
This function performs the computation
This is useful in two different ways. First, if integer is non-negative, then
its value can be represented in unsigned binary form in a field whose width in
bits is no smaller than (integer-length integer). Second, regardless of the
sign of integer, its value can be represented in signed binary two's-complement
form in a field whose width in bits is no smaller than (+ (integer-length
integer) 1). For example:
(integer-length 0) => 0
(integer-length 1) => 1
(integer-length 3) => 2
(integer-length 4) => 3
(integer-length 7) => 3
(integer-length -1) => 0
(integer-length -4) => 2
(integer-length -7) => 3
(integer-length -8) => 3
-------------------------------------------------------------------------------
Compatibility note: This function is similar to the MacLisp function haulong.
One may define haulong as
(haulong x) == (integer-length (abs x))
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
12.8. Byte Manipulation Functions
Several functions are provided for dealing with an arbitrary-width field of
contiguous bits appearing anywhere in an integer. Such a contiguous set of bits
is called a byte. Here the term byte does not imply some fixed number of bits
(such as eight), rather a field of arbitrary and user-specifiable width.
The byte-manipulation functions use objects called byte specifiers to designate
a specific byte position within an integer. The representation of a byte
specifier is implementation-dependent; in particular, it may or may not be a
number. It is sufficient to know that the function byte will construct one, and
that the byte-manipulation functions will accept them. The function byte
accepts two integers representing the position and size of the byte and returns
a byte specifier. Such a specifier designates a byte whose width is size and
whose bits have weights through .
[Function]
byte size position
byte takes two integers representing the size and position of a byte and
returns a byte specifier suitable for use as an argument to byte-manipulation
functions.
[Function]
byte-size bytespec
byte-position bytespec
Given a byte specifier, byte-size returns the size specified as an integer;
byte-position similarly returns the position. For example:
(byte-size (byte j k)) == j
(byte-position (byte j k)) == k
[Function]
ldb bytespec integer
bytespec specifies a byte of integer to be extracted. The result is returned as
a non-negative integer. For example:
(logbitp j (ldb (byte s p) n)) == (and (< j s) (logbitp (+ j p) n))
The name of the function ldb means ``load byte.''
-------------------------------------------------------------------------------
Compatibility note: The MacLisp function haipart can be implemented in terms of
ldb as follows:
(defun haipart (integer count)
(let ((x (abs integer)))
(if (minusp count)
(ldb (byte (- count) 0) x)
(ldb (byte count (max 0 (- (integer-length x) count)))
x))))
-------------------------------------------------------------------------------
If the argument integer is specified by a form that is a place form acceptable
to setf, then setf may be used with ldb to modify a byte within the integer
that is stored in that place. The effect is to perform a dpb operation and then
store the result back into the place.
[Function]
ldb-test bytespec integer
ldb-test is a predicate that is true if any of the bits designated by the byte
specifier bytespec are 1's in integer; that is, it is true if the designated
field is non-zero.
(ldb-test bytespec n) == (not (zerop (ldb bytespec n)))
[Function]
mask-field bytespec integer
This is similar to ldb; however, the result contains the specified byte of
integer in the position specified by bytespec, rather than in position 0 as
with ldb. The result therefore agrees with integer in the byte specified but
has zero-bits everywhere else. For example:
(ldb bs (mask-field bs n)) == (ldb bs n)
(logbitp j (mask-field (byte s p) n))
== (and (>= j p) (< j (+ p s)) (logbitp j n))
(mask-field bs n) == (logand n (dpb -1 bs 0))
If the argument integer is specified by a form that is a place form acceptable
to setf, then setf may be used with mask-field to modify a byte within the
integer that is stored in that place. The effect is to perform a deposit-field
operation and then store the result back into the place.
[Function]
dpb newbyte bytespec integer
This returns a number that is the same as integer except in the bits specified
by bytespec. Let s be the size specified by bytespec; then the low s bits of
newbyte appear in the result in the byte specified by bytespec. The integer
newbyte is therefore interpreted as being right-justified, as if it were the
result of ldb. For example:
(logbitp j (dpb m (byte s p) n))
== (if (and (>= j p) (< j (+ p s)))
(logbitp (- j p) m)
(logbitp j n))
The name of the function dpb means ``deposit byte.''
[Function]
deposit-field newbyte bytespec integer
This function is to mask-field as dpb is to ldb. The result is an integer that
contains the bits of newbyte within the byte specified by bytespec, and
elsewhere contains the bits of integer. For example:
(logbitp j (deposit-field m (byte s p) n))
== (if (and (>= j p) (< j (+ p s)))
(logbitp j m)
(logbitp j n))
-------------------------------------------------------------------------------
Implementation note: If the bytespec is a constant, one may of course
construct, at compile time, an equivalent mask m, for example by computing
(deposit-field -1 bytespec 0). Given this mask m, one may then compute
(deposit-field newbyte bytespec integer)
by computing
(logior (logand newbyte m) (logand integer (lognot m)))
where the result of (lognot m) can of course also be computed at compile time.
However, the following expression may also be used and may require fewer
temporary registers in some situations:
(logxor integer (logand m (logxor integer newbyte)))
A related, though possibly less useful, trick is that
(let ((z (logand (logxor x y) m)))
(setq x (logxor z x))
(setq y (logxor z y)))
interchanges those bits of x and y for which the mask m is 1, and leaves alone
those bits of x and y for which m is 0.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
12.9. Random Numbers
The Common Lisp facility for generating pseudo-random numbers has been
carefully defined to make its use reasonably portable. While two
implementations may produce different series of pseudo-random numbers, the
distribution of values should be relatively independent of such
machine-dependent aspects as word size.
[Function]
random number &optional state
(random n) accepts a positive number n and returns a number of the same kind
between zero (inclusive) and n (exclusive). The number n may be an integer or a
floating-point number. An approximately uniform choice distribution is used. If
n is an integer, each of the possible results occurs with (approximate)
probability
1/n. (The qualifier ``approximate'' is used because of implementation
considerations; in practice, the deviation from uniformity should be quite
small.)
The argument state must be an object of type random-state; it defaults to the
value of the variable *random-state*. This object is used to maintain the state
of the pseudo-random-number generator and is altered as a side effect of the
random operation.
-------------------------------------------------------------------------------
Compatibility note: random of zero arguments as defined in MacLisp has been
omitted because its value is too implementation-dependent (limited by fixnum
range).
-------------------------------------------------------------------------------
Implementation note: In general, even if random of zero arguments were defined
as in MacLisp, it is not adequate to define (random n) for integral n to be
simply (mod (random) n); this fails to be uniformly distributed if n is larger
than the largest number produced by random, or even if n merely approaches this
number. This is another reason for omitting random of zero arguments in Common
Lisp. Assuming that the underlying mechanism produces ``random bits'' (possibly
in chunks such as fixnums), the best approach is to produce enough random bits
to construct an integer k some number d of bits larger than (integer-length n)
(see integer-length), and then compute (mod k n). The quantity d should be at
least 7, and preferably 10 or more.
To produce random floating-point numbers in the half-open range [A, B),
accepted practice (as determined by a look through the Collected Algorithms
from the ACM, particularly algorithms 133, 266, 294, and 370) is to compute
X * (B - A) + A, where X is a floating-point number uniformly distributed over
[0.0, 1.0) and computed by calculating a random integer N in the range [0, M)
(typically by a multiplicative-congruential or linear-congruential method mod
M) and then setting X = N/M. See also [27]. If one takes , where f is the
length of the significand of a floating-point number (and it is in fact common
to choose M to be a power of 2), then this method is equivalent to the
following assembly-language-level procedure. Assume the representation has no
hidden bit. Take a floating-point 0.5, and clobber its entire significand with
random bits. Normalize the result if necessary.
For example, on the DEC PDP-10, assume that accumulator T is completely random
(all 36 bits are random). Then the code sequence
LSH T,-9 ;Clear high 9 bits; low 27 are random
FSC T,128. ;Install exponent and normalize
will produce in T a random floating-point number uniformly distributed over
[0.0, 1.0). (Instead of the LSH instruction, one could do
TLZ T,777000 ;That's 777000 octal
but if the 36 random bits came from a congruential random-number generator, the
high-order bits tend to be ``more random'' than the low-order ones, and so the
LSH would be better for uniform distribution. Ideally all the bits would be the
result of high-quality randomness.)
With a hidden-bit representation, normalization is not a problem, but dealing
with the hidden bit is. The method can be adapted as follows. Take a
floating-point 1.0 and clobber the explicit significand bits with random bits;
this produces a random floating-point number in the range [1.0, 2.0). Then
simply subtract 1.0. In effect, we let the hidden bit creep in and then
subtract it away again.
For example, on the DEC VAX, assume that register T is completely random (but a
little less random than on the PDP-10, as it has only 32 random bits). Then the
code sequence
INSV #^X81,#7,#9,T ;Install correct sign bit and exponent
SUBF #^F1.0,T ;Subtract 1.0
will produce in T a random floating-point number uniformly distributed over
[0.0, 1.0). Again, if the low-order bits are not random enough, then the
instruction
ROTL #7,T
should be performed first.
Implementors may wish to consult reference [41] for a discussion of some
efficient methods of generating pseudo-random numbers.
-------------------------------------------------------------------------------
[Variable]
*random-state*
This variable holds a data structure, an object of type random-state, that
encodes the internal state of the random-number generator that random uses by
default. The nature of this data structure is implementation-dependent. It may
be printed out and successfully read back in, but may or may not function
correctly as a random-number state object in another implementation. A call to
random will perform a side effect on this data structure. Lambda-binding this
variable to a different random-number state object will correctly save and
restore the old state object.
[Function]
make-random-state &optional state
This function returns a new object of type random-state, suitable for use as
the value of the variable *random-state*. If state is nil or omitted,
make-random-state returns a copy of the current random-number state object (the
value of the variable *random-state*). If state is a state object, a copy of
that state object is returned. If state is t, then a new state object is
returned that has been ``randomly'' initialized by some means (such as by a
time-of-day clock).
-------------------------------------------------------------------------------
Rationale: Common Lisp purposely provides no way to initialize a random-state
object from a user-specified ``seed.'' The reason for this is that the number
of bits of state information in a random-state object may vary widely from one
implementation to another, and there is no simple way to guarantee that any
user-specified seed value will be ``random enough.'' Instead, the
initialization of random-state objects is left to the implementor in the case
where the argument t is given to make-random-state.
To handle the common situation of executing the same program many times in a
reproducible manner, where that program uses random, the following procedure
may be used:
1. Evaluate (make-random-state t) to create a random-state object.
2. Write that object to a file, using print, for later use.
3. Whenever the program is to be run, first use read to create a copy of the
random-state object from the printed representation in the file. Then use
the random-state object newly created by the read operation to initialize
the random-number generator for the program.
It is for the sake of this procedure for reproducible execution that
implementations are required to provide a read/print syntax for objects of type
random-state.
It is also possible to make copies of a random-state object directly without
going through the print/read process, simply by using the make-random-state
function to copy the object; this allows the same sequence of random numbers to
be generated many times within a single program.
-------------------------------------------------------------------------------
Implementation note: A recommended way to implement the type random-state is
effectively to use the machinery for defstruct. The usual structure syntax may
then be used for printing random-state objects; one might look something like
#S(RANDOM-STATE DATA #(14 49 98436589 786345 8734658324 ...))
where the components are of course completely implementation-dependent.
-------------------------------------------------------------------------------
[Function]
random-state-p object
random-state-p is true if its argument is a random-state object, and otherwise
is false.
(random-state-p x) == (typep x 'random-state)
-------------------------------------------------------------------------------
12.10 Implementation Parameters
The values of the named constants defined in this section are
implementation-dependent. They may be useful for parameterizing code in some
situations.
[Constant]
most-positive-fixnum
most-negative-fixnum
The value of most-positive-fixnum is that fixnum closest in value to positive
infinity provided by the implementation.
The value of most-negative-fixnum is that fixnum closest in value to negative
infinity provided by the implementation.
[change_begin]
X3J13 voted in January 1989 (FIXNUM-NON-PORTABLE) to specify that fixnum must
be a supertype of the type (signed-byte 16), and additionally that the value of
array-dimension-limit must be a fixnum. This implies that the value of
most-negative-fixnum must be less than or equal to , and the value of
most-positive-fixnum must be greater than or equal to both and the value of
array-dimension-limit.
[change_end]
[Constant]
most-positive-short-float
least-positive-short-float
least-negative-short-float
most-negative-short-float
The value of most-positive-short-float is that short-format floating-point
number closest in value to (but not equal to) positive infinity provided by the
implementation.
The value of least-positive-short-float is that positive short-format
floating-point number closest in value to (but not equal to) zero provided by
the implementation.
The value of least-negative-short-float is that negative short-format
floating-point number closest in value to (but not equal to) zero provided by
the implementation. (Note that even if an implementation supports minus zero as
a distinct short floating-point value, least-negative-short-float must not be
minus zero.)
[change_begin]
X3J13 voted in June 1989 (FLOAT-UNDERFLOW) to clarify that these definitions
are to be taken quite literally. In implementations that support denormalized
numbers, the values of least-positive-short-float and
least-negative-short-float may be denormalized.
[change_end]
The value of most-negative-short-float is that short-format floating-point
number closest in value to (but not equal to) negative infinity provided by the
implementation.
[Constant]
most-positive-single-float
least-positive-single-float
least-negative-single-float
most-negative-single-float
most-positive-double-float
least-positive-double-float
least-negative-double-float
most-negative-double-float
most-positive-long-float
least-positive-long-float
least-negative-long-float
most-negative-long-float
These are analogous to the constants defined above for short-format
floating-point numbers.
[change_begin]
[Constant]
least-positive-normalized-short-float
least-negative-normalized-short-float
X3J13 voted in June 1989 (FLOAT-UNDERFLOW) to add these constants to the
language.
The value of least-positive-normalized-short-float is that positive normalized
short-format floating-point number closest in value to (but not equal to) zero
provided by the implementation. In implementations that do not support
denormalized numbers this may be the same as the value of
least-positive-short-float.
The value of least-negative-normalized-short-float is that negative normalized
short-format floating-point number closest in value to (but not equal to) zero
provided by the implementation. (Note that even if an implementation supports
minus zero as a distinct short floating-point value,
least-negative-normalized-short-float must not be minus zero.) In
implementations that do not support denormalized numbers this may be the same
as the value of least-positive-short-float.
[Constant]
least-positive-normalized-single-float
least-negative-normalized-single-float
least-positive-normalized-double-float
least-negative-normalized-double-float
least-positive-normalized-long-float
least-negative-normalized-long-float
These are analogous to the constants defined above for short-format
floating-point numbers.
[change_end]
[Constant]
short-float-epsilon
single-float-epsilon
double-float-epsilon
long-float-epsilon
These constants have as value, for each floating-point format, the smallest
positive floating-point number e of that format such that the expression
(not (= (float 1 e) (+ (float 1 e) e)))
is true when actually evaluated.
[Constant]
short-float-negative-epsilon
single-float-negative-epsilon
double-float-negative-epsilon
long-float-negative-epsilon
These constants have as value, for each floating-point format, the smallest
positive floating-point number e of that format such that the expression
(not (= (float 1 e) (- (float 1 e) e)))
is true when actually evaluated.
-------------------------------------------------------------------------------